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 *****************************************************************/
15 /* FUNCTIONS *****************************************************************/
22 DbgUiConnectToDbg(VOID
)
24 OBJECT_ATTRIBUTES ObjectAttributes
;
26 /* Don't connect twice */
27 if (NtCurrentTeb()->DbgSsReserved
[1]) return STATUS_SUCCESS
;
29 /* Setup the Attributes */
30 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, 0);
32 /* Create the object */
33 return ZwCreateDebugObject(&NtCurrentTeb()->DbgSsReserved
[1],
34 DEBUG_OBJECT_ALL_ACCESS
,
36 DBGK_KILL_PROCESS_ON_EXIT
);
44 DbgUiContinue(IN PCLIENT_ID ClientId
,
45 IN NTSTATUS ContinueStatus
)
47 /* Tell the kernel object to continue */
48 return ZwDebugContinue(NtCurrentTeb()->DbgSsReserved
[1],
58 DbgUiConvertStateChangeStructure(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange
,
59 OUT PVOID Win32DebugEvent
)
62 OBJECT_ATTRIBUTES ObjectAttributes
;
63 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
64 LPDEBUG_EVENT DebugEvent
= Win32DebugEvent
;
67 /* Write common data */
68 DebugEvent
->dwProcessId
= (DWORD
)WaitStateChange
->
69 AppClientId
.UniqueProcess
;
70 DebugEvent
->dwThreadId
= (DWORD
)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
;
108 case DbgCreateProcessStateChange
:
110 /* Write Win32 debug code */
111 DebugEvent
->dwDebugEventCode
= CREATE_PROCESS_DEBUG_EVENT
;
114 DebugEvent
->u
.CreateProcessInfo
.hProcess
=
115 WaitStateChange
->StateInfo
.CreateProcessInfo
.HandleToProcess
;
116 DebugEvent
->u
.CreateProcessInfo
.hThread
=
117 WaitStateChange
->StateInfo
.CreateProcessInfo
.HandleToThread
;
118 DebugEvent
->u
.CreateProcessInfo
.hFile
=
119 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
121 DebugEvent
->u
.CreateProcessInfo
.lpBaseOfImage
=
122 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
124 DebugEvent
->u
.CreateProcessInfo
.dwDebugInfoFileOffset
=
125 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
127 DebugEvent
->u
.CreateProcessInfo
.nDebugInfoSize
=
128 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
130 DebugEvent
->u
.CreateProcessInfo
.lpStartAddress
=
131 WaitStateChange
->StateInfo
.CreateProcessInfo
.NewProcess
.
132 InitialThread
.StartAddress
;
134 /* Query TEB address */
135 Status
= NtQueryInformationThread(WaitStateChange
->StateInfo
.
136 CreateProcessInfo
.HandleToThread
,
137 ThreadBasicInformation
,
139 sizeof(ThreadBasicInfo
),
141 if (!NT_SUCCESS(Status
))
143 /* Failed to get PEB address */
144 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
= NULL
;
148 /* Write PEB Address */
149 DebugEvent
->u
.CreateProcessInfo
.lpThreadLocalBase
=
150 ThreadBasicInfo
.TebBaseAddress
;
153 /* Clear image name */
154 DebugEvent
->u
.CreateProcessInfo
.lpImageName
= NULL
;
155 DebugEvent
->u
.CreateProcessInfo
.fUnicode
= TRUE
;
159 case DbgExitThreadStateChange
:
161 /* Write the Win32 debug code and the exit status */
162 DebugEvent
->dwDebugEventCode
= EXIT_THREAD_DEBUG_EVENT
;
163 DebugEvent
->u
.ExitThread
.dwExitCode
=
164 WaitStateChange
->StateInfo
.ExitThread
.ExitStatus
;
168 case DbgExitProcessStateChange
:
170 /* Write the Win32 debug code and the exit status */
171 DebugEvent
->dwDebugEventCode
= EXIT_PROCESS_DEBUG_EVENT
;
172 DebugEvent
->u
.ExitProcess
.dwExitCode
=
173 WaitStateChange
->StateInfo
.ExitProcess
.ExitStatus
;
176 /* Any sort of exception */
177 case DbgExceptionStateChange
:
178 case DbgBreakpointStateChange
:
179 case DbgSingleStepStateChange
:
181 /* Check if this was a debug print */
182 if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
183 ExceptionCode
== DBG_PRINTEXCEPTION_C
)
185 /* Set the Win32 code */
186 DebugEvent
->dwDebugEventCode
= OUTPUT_DEBUG_STRING_EVENT
;
188 /* Copy debug string information */
189 DebugEvent
->u
.DebugString
.lpDebugStringData
=
190 (PVOID
)WaitStateChange
->
191 StateInfo
.Exception
.ExceptionRecord
.
192 ExceptionInformation
[1];
193 DebugEvent
->u
.DebugString
.nDebugStringLength
=
194 WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
195 ExceptionInformation
[0];
196 DebugEvent
->u
.DebugString
.fUnicode
= FALSE
;
198 else if (WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
199 ExceptionCode
== DBG_RIPEXCEPTION
)
201 /* Set the Win32 code */
202 DebugEvent
->dwDebugEventCode
= RIP_EVENT
;
204 /* Set exception information */
205 DebugEvent
->u
.RipInfo
.dwType
=
206 WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
207 ExceptionInformation
[1];
208 DebugEvent
->u
.RipInfo
.dwError
=
209 WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
.
210 ExceptionInformation
[0];
214 /* Otherwise, this is a debug event, copy info over */
215 DebugEvent
->dwDebugEventCode
= EXCEPTION_DEBUG_EVENT
;
216 DebugEvent
->u
.Exception
.ExceptionRecord
=
217 WaitStateChange
->StateInfo
.Exception
.ExceptionRecord
;
218 DebugEvent
->u
.Exception
.dwFirstChance
=
219 WaitStateChange
->StateInfo
.Exception
.FirstChance
;
224 case DbgLoadDllStateChange
:
226 /* Set the Win32 debug code */
227 DebugEvent
->dwDebugEventCode
= LOAD_DLL_DEBUG_EVENT
;
229 /* Copy the rest of the data */
230 DebugEvent
->u
.LoadDll
.lpBaseOfDll
=
231 WaitStateChange
->StateInfo
.LoadDll
.BaseOfDll
;
232 DebugEvent
->u
.LoadDll
.hFile
=
233 WaitStateChange
->StateInfo
.LoadDll
.FileHandle
;
234 DebugEvent
->u
.LoadDll
.dwDebugInfoFileOffset
=
235 WaitStateChange
->StateInfo
.LoadDll
.DebugInfoFileOffset
;
236 DebugEvent
->u
.LoadDll
.nDebugInfoSize
=
237 WaitStateChange
->StateInfo
.LoadDll
.DebugInfoSize
;
239 /* Open the thread */
240 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
241 Status
= NtOpenThread(&ThreadHandle
,
242 THREAD_QUERY_INFORMATION
,
244 &WaitStateChange
->AppClientId
);
245 if (NT_SUCCESS(Status
))
247 /* Query thread information */
248 Status
= NtQueryInformationThread(ThreadHandle
,
249 ThreadBasicInformation
,
251 sizeof(ThreadBasicInfo
),
253 NtClose(ThreadHandle
);
256 /* Check if we got thread information */
257 if (NT_SUCCESS(Status
))
259 /* Save the image name from the TIB */
260 DebugEvent
->u
.LoadDll
.lpImageName
=
261 ((PTEB
)ThreadBasicInfo
.TebBaseAddress
)->
262 NtTib
.ArbitraryUserPointer
;
266 /* Otherwise, no name */
267 DebugEvent
->u
.LoadDll
.lpImageName
= NULL
;
271 DebugEvent
->u
.LoadDll
.fUnicode
= TRUE
;
275 case DbgUnloadDllStateChange
:
277 /* Set Win32 code and DLL Base */
278 DebugEvent
->dwDebugEventCode
= UNLOAD_DLL_DEBUG_EVENT
;
279 DebugEvent
->u
.UnloadDll
.lpBaseOfDll
=
280 WaitStateChange
->StateInfo
.UnloadDll
.BaseAddress
;
283 /* Anything else, fail */
284 default: return STATUS_UNSUCCESSFUL
;
288 return STATUS_SUCCESS
;
296 DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE DbgUiWaitStateCange
,
297 IN PLARGE_INTEGER TimeOut OPTIONAL
)
299 /* Tell the kernel to wait */
300 return NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved
[1],
303 DbgUiWaitStateCange
);
311 DbgUiRemoteBreakin(VOID
)
313 /* Make sure a debugger is enabled; if so, breakpoint */
314 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
316 /* Exit the thread */
317 RtlExitUserThread(STATUS_SUCCESS
);
325 DbgUiIssueRemoteBreakin(IN HANDLE Process
)
331 /* Create the thread that will do the breakin */
332 Status
= RtlCreateUserThread(Process
,
338 (PVOID
)DbgUiRemoteBreakin
,
343 /* Close the handle on success */
344 if(NT_SUCCESS(Status
)) NtClose(hThread
);
355 DbgUiGetThreadDebugObject(VOID
)
357 /* Just return the handle from the TEB */
358 return NtCurrentTeb()->DbgSsReserved
[1];
366 DbgUiSetThreadDebugObject(HANDLE DebugObject
)
368 /* Just set the handle in the TEB */
369 NtCurrentTeb()->DbgSsReserved
[1] = DebugObject
;
377 DbgUiDebugActiveProcess(IN HANDLE Process
)
381 /* Tell the kernel to start debugging */
382 Status
= NtDebugActiveProcess(Process
, NtCurrentTeb()->DbgSsReserved
[1]);
383 if (NT_SUCCESS(Status
))
385 /* Now break-in the process */
386 Status
= DbgUiIssueRemoteBreakin(Process
);
387 if (!NT_SUCCESS(Status
))
389 /* We couldn't break-in, cancel debugging */
390 DbgUiStopDebugging(Process
);
403 DbgUiStopDebugging(IN HANDLE Process
)
405 /* Call the kernel to remove the debug object */
406 return NtRemoveProcessDebug(Process
, NtCurrentTeb()->DbgSsReserved
[1]);