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 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
66 LPDEBUG_EVENT DebugEvent
= Win32DebugEvent
;
68 /* Write common data */
69 DebugEvent
->dwProcessId
= (DWORD
)WaitStateChange
->
70 AppClientId
.UniqueProcess
;
71 DebugEvent
->dwThreadId
= (DWORD
)WaitStateChange
->AppClientId
.UniqueThread
;
73 /* Check what kind of even this is */
74 switch (WaitStateChange
->NewState
)
77 case DbgCreateThreadStateChange
:
79 /* Setup Win32 code */
80 DebugEvent
->dwDebugEventCode
= CREATE_THREAD_DEBUG_EVENT
;
83 DebugEvent
->u
.CreateThread
.hThread
=
84 WaitStateChange
->StateInfo
.CreateThread
.HandleToThread
;
85 DebugEvent
->u
.CreateThread
.lpStartAddress
=
86 WaitStateChange
->StateInfo
.CreateThread
.NewThread
.StartAddress
;
89 Status
= NtQueryInformationThread(WaitStateChange
->StateInfo
.
90 CreateThread
.HandleToThread
,
91 ThreadBasicInformation
,
93 sizeof(ThreadBasicInfo
),
95 if (!NT_SUCCESS(Status
))
97 /* Failed to get PEB address */
98 DebugEvent
->u
.CreateThread
.lpThreadLocalBase
= NULL
;
102 /* Write PEB Address */
103 DebugEvent
->u
.CreateThread
.lpThreadLocalBase
=
104 ThreadBasicInfo
.TebBaseAddress
;
110 case DbgCreateProcessStateChange
:
112 /* Write Win32 debug code */
113 DebugEvent
->dwDebugEventCode
= CREATE_PROCESS_DEBUG_EVENT
;
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
.
123 DebugEvent
->u
.CreateProcessInfo
.lpBaseOfImage
=
124 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
126 DebugEvent
->u
.CreateProcessInfo
.dwDebugInfoFileOffset
=
127 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
129 DebugEvent
->u
.CreateProcessInfo
.nDebugInfoSize
=
130 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
132 DebugEvent
->u
.CreateProcessInfo
.lpStartAddress
=
133 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
134 InitialThread
.StartAddress
;
136 /* Query TEB address */
137 Status
= NtQueryInformationThread(WaitStateChange
->StateInfo
.
138 CreateProcessInfo
.HandleToThread
,
139 ThreadBasicInformation
,
141 sizeof(ThreadBasicInfo
),
143 if (!NT_SUCCESS(Status
))
145 /* Failed to get PEB address */
146 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
= NULL
;
150 /* Write PEB Address */
151 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
=
152 ThreadBasicInfo
.TebBaseAddress
;
155 /* Clear image name */
156 DebugEvent
->u
.CreateProcessInfo
.lpImageName
= NULL
;
157 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
;
172 case DbgExitProcessStateChange
:
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
;
181 /* Any sort of exception */
182 case DbgExceptionStateChange
:
183 case DbgBreakpointStateChange
:
184 case DbgSingleStepStateChange
:
186 /* Check if this was a debug print */
187 if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
188 ExceptionCode
== DBG_PRINTEXCEPTION_C
)
190 /* Set the Win32 code */
191 DebugEvent
->dwDebugEventCode
= OUTPUT_DEBUG_STRING_EVENT
;
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
;
203 else if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
204 ExceptionCode
== DBG_RIPEXCEPTION
)
206 /* Set the Win32 code */
207 DebugEvent
->dwDebugEventCode
= RIP_EVENT
;
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];
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
;
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
.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
;
248 DebugEvent
->u
.LoadDll
.fUnicode
= TRUE
;
253 case DbgUnloadDllStateChange
:
255 /* Set Win32 code and DLL Base */
256 DebugEvent
->dwDebugEventCode
= UNLOAD_DLL_DEBUG_EVENT
;
257 DebugEvent
->u
.UnloadDll
.lpBaseOfDll
=
258 WaitStateChange
->StateInfo
.UnloadDll
.BaseAddress
;
262 /* Anything else, fail */
263 default: return STATUS_UNSUCCESSFUL
;
267 return STATUS_SUCCESS
;
275 DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE DbgUiWaitStateCange
,
276 IN PLARGE_INTEGER TimeOut OPTIONAL
)
278 /* Tell the kernel to wait */
279 return NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved
[1],
282 DbgUiWaitStateCange
);
290 DbgUiRemoteBreakin(VOID
)
292 /* Make sure a debugger is enabled; if so, breakpoint */
293 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
295 /* Exit the thread */
296 RtlExitUserThread(STATUS_SUCCESS
);
304 DbgUiIssueRemoteBreakin(IN HANDLE Process
)
310 /* Create the thread that will do the breakin */
311 Status
= RtlCreateUserThread(Process
,
317 (PVOID
)DbgUiRemoteBreakin
,
322 /* Close the handle on success */
323 if(NT_SUCCESS(Status
)) NtClose(hThread
);
334 DbgUiGetThreadDebugObject(VOID
)
336 /* Just return the handle from the TEB */
337 return NtCurrentTeb()->DbgSsReserved
[1];
345 DbgUiSetThreadDebugObject(HANDLE DebugObject
)
347 /* Just set the handle in the TEB */
348 NtCurrentTeb()->DbgSsReserved
[1] = DebugObject
;
356 DbgUiDebugActiveProcess(IN HANDLE Process
)
360 /* Tell the kernel to start debugging */
361 Status
= NtDebugActiveProcess(Process
, NtCurrentTeb()->DbgSsReserved
[1]);
362 if (NT_SUCCESS(Status
))
364 /* Now break-in the process */
365 Status
= DbgUiIssueRemoteBreakin(Process
);
366 if (!NT_SUCCESS(Status
))
368 /* We couldn't break-in, cancel debugging */
369 DbgUiStopDebugging(Process
);
382 DbgUiStopDebugging(IN HANDLE Process
)
384 /* Call the kernel to remove the debug object */
385 return NtRemoveProcessDebug(Process
, NtCurrentTeb()->DbgSsReserved
[1]);