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
;
70 /* Write common data */
71 DebugEvent
->dwProcessId
= (DWORD
)WaitStateChange
->
72 AppClientId
.UniqueProcess
;
73 DebugEvent
->dwThreadId
= (DWORD
)WaitStateChange
->AppClientId
.UniqueThread
;
75 /* Check what kind of even this is */
76 switch (WaitStateChange
->NewState
)
79 case DbgCreateThreadStateChange
:
81 /* Setup Win32 code */
82 DebugEvent
->dwDebugEventCode
= CREATE_THREAD_DEBUG_EVENT
;
85 DebugEvent
->u
.CreateThread
.hThread
=
86 WaitStateChange
->StateInfo
.CreateThread
.HandleToThread
;
87 DebugEvent
->u
.CreateThread
.lpStartAddress
=
88 WaitStateChange
->StateInfo
.CreateThread
.NewThread
.StartAddress
;
91 Status
= NtQueryInformationThread(WaitStateChange
->StateInfo
.
92 CreateThread
.HandleToThread
,
93 ThreadBasicInformation
,
95 sizeof(ThreadBasicInfo
),
97 if (!NT_SUCCESS(Status
))
99 /* Failed to get PEB address */
100 DebugEvent
->u
.CreateThread
.lpThreadLocalBase
= NULL
;
104 /* Write PEB Address */
105 DebugEvent
->u
.CreateThread
.lpThreadLocalBase
=
106 ThreadBasicInfo
.TebBaseAddress
;
111 case DbgCreateProcessStateChange
:
113 /* Write Win32 debug code */
114 DebugEvent
->dwDebugEventCode
= CREATE_PROCESS_DEBUG_EVENT
;
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
.
124 DebugEvent
->u
.CreateProcessInfo
.lpBaseOfImage
=
125 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
127 DebugEvent
->u
.CreateProcessInfo
.dwDebugInfoFileOffset
=
128 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
130 DebugEvent
->u
.CreateProcessInfo
.nDebugInfoSize
=
131 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
133 DebugEvent
->u
.CreateProcessInfo
.lpStartAddress
=
134 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
135 InitialThread
.StartAddress
;
137 /* Query TEB address */
138 Status
= NtQueryInformationThread(WaitStateChange
->StateInfo
.
139 CreateProcessInfo
.HandleToThread
,
140 ThreadBasicInformation
,
142 sizeof(ThreadBasicInfo
),
144 if (!NT_SUCCESS(Status
))
146 /* Failed to get PEB address */
147 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
= NULL
;
151 /* Write PEB Address */
152 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
=
153 ThreadBasicInfo
.TebBaseAddress
;
156 /* Clear image name */
157 DebugEvent
->u
.CreateProcessInfo
.lpImageName
= NULL
;
158 DebugEvent
->u
.CreateProcessInfo
.fUnicode
= TRUE
;
162 case DbgExitThreadStateChange
:
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
;
171 case DbgExitProcessStateChange
:
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
;
179 /* Any sort of exception */
180 case DbgExceptionStateChange
:
181 case DbgBreakpointStateChange
:
182 case DbgSingleStepStateChange
:
184 /* Check if this was a debug print */
185 if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
186 ExceptionCode
== DBG_PRINTEXCEPTION_C
)
188 /* Set the Win32 code */
189 DebugEvent
->dwDebugEventCode
= OUTPUT_DEBUG_STRING_EVENT
;
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
;
201 else if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
202 ExceptionCode
== DBG_RIPEXCEPTION
)
204 /* Set the Win32 code */
205 DebugEvent
->dwDebugEventCode
= RIP_EVENT
;
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];
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
;
227 case DbgLoadDllStateChange
:
229 /* Set the Win32 debug code */
230 DebugEvent
->dwDebugEventCode
= LOAD_DLL_DEBUG_EVENT
;
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
;
242 /* Open the thread */
243 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
244 Status
= NtOpenThread(&ThreadHandle
,
245 THREAD_QUERY_INFORMATION
,
247 &WaitStateChange
->AppClientId
);
248 if (NT_SUCCESS(Status
))
250 /* Query thread information */
251 Status
= NtQueryInformationThread(ThreadHandle
,
252 ThreadBasicInformation
,
254 sizeof(ThreadBasicInfo
),
256 NtClose(ThreadHandle
);
259 /* Check if we got thread information */
260 if (NT_SUCCESS(Status
))
262 /* Save the image name from the TIB */
263 DebugEvent
->u
.LoadDll
.lpImageName
=
264 ((PTEB
)ThreadBasicInfo
.TebBaseAddress
)->
265 NtTib
.ArbitraryUserPointer
;
269 /* Otherwise, no name */
270 DebugEvent
->u
.LoadDll
.lpImageName
= NULL
;
274 DebugEvent
->u
.LoadDll
.fUnicode
= TRUE
;
278 case DbgUnloadDllStateChange
:
280 /* Set Win32 code and DLL Base */
281 DebugEvent
->dwDebugEventCode
= UNLOAD_DLL_DEBUG_EVENT
;
282 DebugEvent
->u
.UnloadDll
.lpBaseOfDll
=
283 WaitStateChange
->StateInfo
.UnloadDll
.BaseAddress
;
286 /* Anything else, fail */
287 default: return STATUS_UNSUCCESSFUL
;
291 return STATUS_SUCCESS
;
299 DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE DbgUiWaitStateCange
,
300 IN PLARGE_INTEGER TimeOut OPTIONAL
)
302 /* Tell the kernel to wait */
303 return NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved
[1],
306 DbgUiWaitStateCange
);
314 DbgUiRemoteBreakin(VOID
)
316 /* Make sure a debugger is enabled; if so, breakpoint */
317 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
319 /* Exit the thread */
320 RtlExitUserThread(STATUS_SUCCESS
);
328 DbgUiIssueRemoteBreakin(IN HANDLE Process
)
334 /* Create the thread that will do the breakin */
335 Status
= RtlCreateUserThread(Process
,
341 (PVOID
)DbgUiRemoteBreakin
,
346 /* Close the handle on success */
347 if(NT_SUCCESS(Status
)) NtClose(hThread
);
358 DbgUiGetThreadDebugObject(VOID
)
360 /* Just return the handle from the TEB */
361 return NtCurrentTeb()->DbgSsReserved
[1];
369 DbgUiSetThreadDebugObject(HANDLE DebugObject
)
371 /* Just set the handle in the TEB */
372 NtCurrentTeb()->DbgSsReserved
[1] = DebugObject
;
380 DbgUiDebugActiveProcess(IN HANDLE Process
)
384 /* Tell the kernel to start debugging */
385 Status
= NtDebugActiveProcess(Process
, NtCurrentTeb()->DbgSsReserved
[1]);
386 if (NT_SUCCESS(Status
))
388 /* Now break-in the process */
389 Status
= DbgUiIssueRemoteBreakin(Process
);
390 if (!NT_SUCCESS(Status
))
392 /* We couldn't break-in, cancel debugging */
393 DbgUiStopDebugging(Process
);
406 DbgUiStopDebugging(IN HANDLE Process
)
408 /* Call the kernel to remove the debug object */
409 return NtRemoveProcessDebug(Process
, NtCurrentTeb()->DbgSsReserved
[1]);