ReactOS  0.4.13-dev-99-g7e18b6d
dbgui.c
Go to the documentation of this file.
1 /*
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)
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <ntdll.h>
12 
13 #include <ndk/dbgkfuncs.h>
14 
15 #define NDEBUG
16 #include <debug.h>
17 
18 /* FUNCTIONS *****************************************************************/
19 
20 /*
21  * @implemented
22  */
24 NTAPI
26 {
28 
29  /* Don't connect twice */
30  if (NtCurrentTeb()->DbgSsReserved[1]) return STATUS_SUCCESS;
31 
32  /* Setup the Attributes */
34 
35  /* Create the object */
36  return ZwCreateDebugObject(&NtCurrentTeb()->DbgSsReserved[1],
40 }
41 
42 /*
43  * @implemented
44  */
46 NTAPI
48  IN NTSTATUS ContinueStatus)
49 {
50  /* Tell the kernel object to continue */
51  return ZwDebugContinue(NtCurrentTeb()->DbgSsReserved[1],
52  ClientId,
53  ContinueStatus);
54 }
55 
56 /*
57  * @implemented
58  */
60 NTAPI
62  OUT PVOID Win32DebugEvent)
63 {
65  THREAD_BASIC_INFORMATION ThreadBasicInfo;
66  LPDEBUG_EVENT DebugEvent = Win32DebugEvent;
67 
68  /* Write common data */
69  DebugEvent->dwProcessId = PtrToUlong(WaitStateChange->AppClientId.UniqueProcess);
70  DebugEvent->dwThreadId = PtrToUlong(WaitStateChange->AppClientId.UniqueThread);
71 
72  /* Check what kind of even this is */
73  switch (WaitStateChange->NewState)
74  {
75  /* New thread */
77  {
78  /* Setup Win32 code */
79  DebugEvent->dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT;
80 
81  /* Copy data over */
82  DebugEvent->u.CreateThread.hThread =
83  WaitStateChange->StateInfo.CreateThread.HandleToThread;
84  DebugEvent->u.CreateThread.lpStartAddress =
85  WaitStateChange->StateInfo.CreateThread.NewThread.StartAddress;
86 
87  /* Query the TEB */
88  Status = NtQueryInformationThread(WaitStateChange->StateInfo.
89  CreateThread.HandleToThread,
91  &ThreadBasicInfo,
92  sizeof(ThreadBasicInfo),
93  NULL);
94  if (!NT_SUCCESS(Status))
95  {
96  /* Failed to get PEB address */
97  DebugEvent->u.CreateThread.lpThreadLocalBase = NULL;
98  }
99  else
100  {
101  /* Write PEB Address */
102  DebugEvent->u.CreateThread.lpThreadLocalBase =
103  ThreadBasicInfo.TebBaseAddress;
104  }
105  break;
106  }
107 
108  /* New process */
110  {
111  /* Write Win32 debug code */
112  DebugEvent->dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT;
113 
114  /* Copy data over */
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.
121  FileHandle;
122  DebugEvent->u.CreateProcessInfo.lpBaseOfImage =
123  WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
124  BaseOfImage;
125  DebugEvent->u.CreateProcessInfo.dwDebugInfoFileOffset =
126  WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
127  DebugInfoFileOffset;
128  DebugEvent->u.CreateProcessInfo.nDebugInfoSize =
129  WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
130  DebugInfoSize;
131  DebugEvent->u.CreateProcessInfo.lpStartAddress =
132  WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.
133  InitialThread.StartAddress;
134 
135  /* Query TEB address */
136  Status = NtQueryInformationThread(WaitStateChange->StateInfo.
137  CreateProcessInfo.HandleToThread,
139  &ThreadBasicInfo,
140  sizeof(ThreadBasicInfo),
141  NULL);
142  if (!NT_SUCCESS(Status))
143  {
144  /* Failed to get PEB address */
145  DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = NULL;
146  }
147  else
148  {
149  /* Write PEB Address */
150  DebugEvent->u.CreateProcessInfo.lpThreadLocalBase =
151  ThreadBasicInfo.TebBaseAddress;
152  }
153 
154  /* Clear image name */
155  DebugEvent->u.CreateProcessInfo.lpImageName = NULL;
156  DebugEvent->u.CreateProcessInfo.fUnicode = TRUE;
157  break;
158  }
159 
160  /* Thread exited */
162  {
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;
167  break;
168  }
169 
170  /* Process exited */
172  {
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;
177  break;
178  }
179 
180  /* Any sort of exception */
184  {
185  /* Check if this was a debug print */
186  if (WaitStateChange->StateInfo.Exception.ExceptionRecord.
188  {
189  /* Set the Win32 code */
190  DebugEvent->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;
191 
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;
201  }
202  else if (WaitStateChange->StateInfo.Exception.ExceptionRecord.
204  {
205  /* Set the Win32 code */
206  DebugEvent->dwDebugEventCode = RIP_EVENT;
207 
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];
215  }
216  else
217  {
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;
224  }
225  break;
226  }
227 
228  /* DLL Load */
230  {
231  /* Set the Win32 debug code */
232  DebugEvent->dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
233 
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;
245 
246  /* It's Unicode */
247  DebugEvent->u.LoadDll.fUnicode = TRUE;
248  break;
249  }
250 
251  /* DLL Unload */
253  {
254  /* Set Win32 code and DLL Base */
255  DebugEvent->dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
256  DebugEvent->u.UnloadDll.lpBaseOfDll =
257  WaitStateChange->StateInfo.UnloadDll.BaseAddress;
258  break;
259  }
260 
261  /* Anything else, fail */
262  default: return STATUS_UNSUCCESSFUL;
263  }
264 
265  /* Return success */
266  return STATUS_SUCCESS;
267 }
268 
269 /*
270  * @implemented
271  */
272 NTSTATUS
273 NTAPI
275  IN PLARGE_INTEGER TimeOut OPTIONAL)
276 {
277  /* Tell the kernel to wait */
278  return NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved[1],
279  TRUE,
280  TimeOut,
281  WaitStateChange);
282 }
283 
284 /*
285  * @implemented
286  */
287 VOID
288 NTAPI
290 {
291  /* Make sure a debugger is enabled; if so, breakpoint */
292  if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
293 
294  /* Exit the thread */
296 }
297 
298 /*
299  * @implemented
300  */
301 NTSTATUS
302 NTAPI
304 {
305  HANDLE hThread;
308 
309  /* Create the thread that will do the breakin */
311  NULL,
312  FALSE,
313  0,
314  0,
315  PAGE_SIZE,
317  NULL,
318  &hThread,
319  &ClientId);
320 
321  /* Close the handle on success */
323 
324  /* Return status */
325  return Status;
326 }
327 
328 /*
329  * @implemented
330  */
331 HANDLE
332 NTAPI
334 {
335  /* Just return the handle from the TEB */
336  return NtCurrentTeb()->DbgSsReserved[1];
337 }
338 
339 /*
340 * @implemented
341 */
342 VOID
343 NTAPI
345 {
346  /* Just set the handle in the TEB */
347  NtCurrentTeb()->DbgSsReserved[1] = DebugObject;
348 }
349 
350 /*
351  * @implemented
352  */
353 NTSTATUS
354 NTAPI
356 {
358 
359  /* Tell the kernel to start debugging */
360  Status = NtDebugActiveProcess(Process, NtCurrentTeb()->DbgSsReserved[1]);
361  if (NT_SUCCESS(Status))
362  {
363  /* Now break-in the process */
365  if (!NT_SUCCESS(Status))
366  {
367  /* We couldn't break-in, cancel debugging */
369  }
370  }
371 
372  /* Return status */
373  return Status;
374 }
375 
376 /*
377  * @implemented
378  */
379 NTSTATUS
380 NTAPI
382 {
383  /* Call the kernel to remove the debug object */
384  return NtRemoveProcessDebug(Process, NtCurrentTeb()->DbgSsReserved[1]);
385 }
386 
387 /* EOF */
HANDLE NTAPI DbgUiGetThreadDebugObject(VOID)
Definition: dbgui.c:333
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
_Inout_ PIRP _In_ NTSTATUS ExceptionCode
Definition: cdprocs.h:1782
NTSTATUS NTAPI DbgUiConnectToDbg(VOID)
Definition: dbgui.c:25
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
VOID NTAPI DbgUiSetThreadDebugObject(HANDLE DebugObject)
Definition: dbgui.c:344
VOID NTAPI DbgUiRemoteBreakin(VOID)
Definition: dbgui.c:289
NTSYSAPI VOID NTAPI RtlExitUserThread(_In_ NTSTATUS Status)
NTSTATUS NTAPI DbgUiStopDebugging(IN HANDLE Process)
Definition: dbgui.c:381
LONG NTSTATUS
Definition: precomp.h:26
#define DBGK_KILL_PROCESS_ON_EXIT
Definition: dbgktypes.h:49
NTSTATUS NTAPI NtRemoveProcessDebug(IN HANDLE ProcessHandle, IN HANDLE DebugHandle)
Definition: dbgkobj.c:1873
NTSTATUS NTAPI NtDebugActiveProcess(IN HANDLE ProcessHandle, IN HANDLE DebugHandle)
Definition: dbgkobj.c:1797
#define DebugEvent(tess)
Definition: sweep.c:59
#define LOAD_DLL_DEBUG_EVENT
Definition: winbase.h:107
void DbgBreakPoint()
Definition: mach.c:558
NTSYSAPI NTSTATUS NTAPI ZwDebugContinue(_In_ HANDLE DebugObject, _In_ PCLIENT_ID AppClientId, _In_ NTSTATUS ContinueStatus)
HANDLE FileHandle
Definition: stats.c:38
NTSTATUS NTAPI NtWaitForDebugEvent(IN HANDLE DebugHandle, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL, OUT PDBGUI_WAIT_STATE_CHANGE StateChange)
Definition: dbgkobj.c:2001
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:112
smooth NULL
Definition: ftsmooth.c:416
#define UNLOAD_DLL_DEBUG_EVENT
Definition: winbase.h:108
SIZE_T LPDEBUG_EVENT
Definition: cordebug.idl:83
void * PVOID
Definition: retypes.h:9
NTSTATUS NTAPI DbgUiContinue(IN PCLIENT_ID ClientId, IN NTSTATUS ContinueStatus)
Definition: dbgui.c:47
#define PtrToUlong(u)
Definition: config.h:107
NTSTATUS NTAPI DbgUiDebugActiveProcess(IN HANDLE Process)
Definition: dbgui.c:355
#define EXIT_PROCESS_DEBUG_EVENT
Definition: winbase.h:106
_Out_ PCLIENT_ID ClientId
Definition: kefuncs.h:1176
#define CREATE_THREAD_DEBUG_EVENT
Definition: winbase.h:103
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
NTSTATUS NTAPI NtQueryInformationThread(IN HANDLE ThreadHandle, IN THREADINFOCLASS ThreadInformationClass, OUT PVOID ThreadInformation, IN ULONG ThreadInformationLength, OUT PULONG ReturnLength OPTIONAL)
Definition: query.c:2450
NTSTATUS NTAPI DbgUiConvertStateChangeStructure(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange, OUT PVOID Win32DebugEvent)
Definition: dbgui.c:61
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
NTSTATUS NTAPI DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE WaitStateChange, IN PLARGE_INTEGER TimeOut OPTIONAL)
Definition: dbgui.c:274
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
NTSTATUS NTAPI DbgUiIssueRemoteBreakin(IN HANDLE Process)
Definition: dbgui.c:303
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define DBG_PRINTEXCEPTION_C
Definition: ntstatus.h:53
NTSYSAPI NTSTATUS NTAPI RtlCreateUserThread(_In_ PVOID ThreadContext, _Out_ HANDLE *OutThreadHandle, _Reserved_ PVOID Reserved1, _Reserved_ PVOID Reserved2, _Reserved_ PVOID Reserved3, _Reserved_ PVOID Reserved4, _Reserved_ PVOID Reserved5, _Reserved_ PVOID Reserved6, _Reserved_ PVOID Reserved7, _Reserved_ PVOID Reserved8)
Status
Definition: gdiplustypes.h:24
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
NTSYSAPI NTSTATUS NTAPI ZwCreateDebugObject(_Out_ PHANDLE DebugHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ ULONG Flags)
#define NtCurrentPeb()
Definition: FLS.c:19
#define EXCEPTION_DEBUG_EVENT
Definition: winbase.h:102
#define DBG_RIPEXCEPTION
Definition: ntstatus.h:54
HANDLE hThread
Definition: wizard.c:27
#define EXIT_THREAD_DEBUG_EVENT
Definition: winbase.h:105
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
#define OUT
Definition: typedefs.h:39
#define OUTPUT_DEBUG_STRING_EVENT
Definition: winbase.h:109
#define DEBUG_OBJECT_ALL_ACCESS
Definition: dbgktypes.h:34
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define CREATE_PROCESS_DEBUG_EVENT
Definition: winbase.h:104
return STATUS_SUCCESS
Definition: btrfs.c:2725
#define RIP_EVENT
Definition: winbase.h:110
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68