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
= PtrToUlong(WaitStateChange
->AppClientId
.UniqueProcess
);
70 DebugEvent
->dwThreadId
= PtrToUlong(WaitStateChange
->AppClientId
.UniqueThread
);
72 /* Check what kind of even this is */
73 switch (WaitStateChange
->NewState
)
76 case DbgCreateThreadStateChange
:
78 /* Setup Win32 code */
79 DebugEvent
->dwDebugEventCode
= CREATE_THREAD_DEBUG_EVENT
;
82 DebugEvent
->u
.CreateThread
.hThread
=
83 WaitStateChange
->StateInfo
.CreateThread
.HandleToThread
;
84 DebugEvent
->u
.CreateThread
.lpStartAddress
=
85 WaitStateChange
->StateInfo
.CreateThread
.NewThread
.StartAddress
;
88 Status
= NtQueryInformationThread(WaitStateChange
->StateInfo
.
89 CreateThread
.HandleToThread
,
90 ThreadBasicInformation
,
92 sizeof(ThreadBasicInfo
),
94 if (!NT_SUCCESS(Status
))
96 /* Failed to get PEB address */
97 DebugEvent
->u
.CreateThread
.lpThreadLocalBase
= NULL
;
101 /* Write PEB Address */
102 DebugEvent
->u
.CreateThread
.lpThreadLocalBase
=
103 ThreadBasicInfo
.TebBaseAddress
;
109 case DbgCreateProcessStateChange
:
111 /* Write Win32 debug code */
112 DebugEvent
->dwDebugEventCode
= CREATE_PROCESS_DEBUG_EVENT
;
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
.
122 DebugEvent
->u
.CreateProcessInfo
.lpBaseOfImage
=
123 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
125 DebugEvent
->u
.CreateProcessInfo
.dwDebugInfoFileOffset
=
126 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
128 DebugEvent
->u
.CreateProcessInfo
.nDebugInfoSize
=
129 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
131 DebugEvent
->u
.CreateProcessInfo
.lpStartAddress
=
132 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
133 InitialThread
.StartAddress
;
135 /* Query TEB address */
136 Status
= NtQueryInformationThread(WaitStateChange
->StateInfo
.
137 CreateProcessInfo
.HandleToThread
,
138 ThreadBasicInformation
,
140 sizeof(ThreadBasicInfo
),
142 if (!NT_SUCCESS(Status
))
144 /* Failed to get PEB address */
145 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
= NULL
;
149 /* Write PEB Address */
150 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
=
151 ThreadBasicInfo
.TebBaseAddress
;
154 /* Clear image name */
155 DebugEvent
->u
.CreateProcessInfo
.lpImageName
= NULL
;
156 DebugEvent
->u
.CreateProcessInfo
.fUnicode
= TRUE
;
161 case DbgExitThreadStateChange
:
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
;
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
;
180 /* Any sort of exception */
181 case DbgExceptionStateChange
:
182 case DbgBreakpointStateChange
:
183 case DbgSingleStepStateChange
:
185 /* Check if this was a debug print */
186 if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
187 ExceptionCode
== DBG_PRINTEXCEPTION_C
)
189 /* Set the Win32 code */
190 DebugEvent
->dwDebugEventCode
= OUTPUT_DEBUG_STRING_EVENT
;
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
;
202 else if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
203 ExceptionCode
== DBG_RIPEXCEPTION
)
205 /* Set the Win32 code */
206 DebugEvent
->dwDebugEventCode
= RIP_EVENT
;
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];
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
;
229 case DbgLoadDllStateChange
:
231 /* Set the Win32 debug code */
232 DebugEvent
->dwDebugEventCode
= LOAD_DLL_DEBUG_EVENT
;
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
;
247 DebugEvent
->u
.LoadDll
.fUnicode
= TRUE
;
252 case DbgUnloadDllStateChange
:
254 /* Set Win32 code and DLL Base */
255 DebugEvent
->dwDebugEventCode
= UNLOAD_DLL_DEBUG_EVENT
;
256 DebugEvent
->u
.UnloadDll
.lpBaseOfDll
=
257 WaitStateChange
->StateInfo
.UnloadDll
.BaseAddress
;
261 /* Anything else, fail */
262 default: return STATUS_UNSUCCESSFUL
;
266 return STATUS_SUCCESS
;
274 DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE WaitStateChange
,
275 IN PLARGE_INTEGER TimeOut OPTIONAL
)
277 /* Tell the kernel to wait */
278 return NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved
[1],
289 DbgUiRemoteBreakin(VOID
)
291 /* Make sure a debugger is enabled; if so, breakpoint */
292 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
294 /* Exit the thread */
295 RtlExitUserThread(STATUS_SUCCESS
);
303 DbgUiIssueRemoteBreakin(IN HANDLE Process
)
309 /* Create the thread that will do the breakin */
310 Status
= RtlCreateUserThread(Process
,
316 (PVOID
)DbgUiRemoteBreakin
,
321 /* Close the handle on success */
322 if(NT_SUCCESS(Status
)) NtClose(hThread
);
333 DbgUiGetThreadDebugObject(VOID
)
335 /* Just return the handle from the TEB */
336 return NtCurrentTeb()->DbgSsReserved
[1];
344 DbgUiSetThreadDebugObject(HANDLE DebugObject
)
346 /* Just set the handle in the TEB */
347 NtCurrentTeb()->DbgSsReserved
[1] = DebugObject
;
355 DbgUiDebugActiveProcess(IN HANDLE Process
)
359 /* Tell the kernel to start debugging */
360 Status
= NtDebugActiveProcess(Process
, NtCurrentTeb()->DbgSsReserved
[1]);
361 if (NT_SUCCESS(Status
))
363 /* Now break-in the process */
364 Status
= DbgUiIssueRemoteBreakin(Process
);
365 if (!NT_SUCCESS(Status
))
367 /* We couldn't break-in, cancel debugging */
368 DbgUiStopDebugging(Process
);
381 DbgUiStopDebugging(IN HANDLE Process
)
383 /* Call the kernel to remove the debug object */
384 return NtRemoveProcessDebug(Process
, NtCurrentTeb()->DbgSsReserved
[1]);