xref: /reactos/ntoskrnl/dbgk/dbgkutil.c (revision c2c66aff)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/dbgk/dbgkutil.c
5  * PURPOSE:         User-Mode Debugging Support, Internal Debug Functions.
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* FUNCTIONS *****************************************************************/
16 
17 HANDLE
18 NTAPI
DbgkpSectionToFileHandle(IN PVOID Section)19 DbgkpSectionToFileHandle(IN PVOID Section)
20 {
21     NTSTATUS Status;
22     POBJECT_NAME_INFORMATION FileName;
23     OBJECT_ATTRIBUTES ObjectAttributes;
24     IO_STATUS_BLOCK IoStatusBlock;
25     HANDLE Handle;
26     PAGED_CODE();
27 
28     /* Get the filename of the section */
29     Status = MmGetFileNameForSection(Section, &FileName);
30     if (!NT_SUCCESS(Status)) return NULL;
31 
32     /* Initialize object attributes */
33     InitializeObjectAttributes(&ObjectAttributes,
34                                &FileName->Name,
35                                OBJ_CASE_INSENSITIVE |
36                                OBJ_FORCE_ACCESS_CHECK |
37                                OBJ_KERNEL_HANDLE,
38                                NULL,
39                                NULL);
40 
41     /* Open the file */
42     Status = ZwOpenFile(&Handle,
43                         GENERIC_READ | SYNCHRONIZE,
44                         &ObjectAttributes,
45                         &IoStatusBlock,
46                         FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
47                         FILE_SYNCHRONOUS_IO_NONALERT);
48 
49     /* Free the name and return the handle if we succeeded */
50     ExFreePool(FileName);
51     if (!NT_SUCCESS(Status)) return NULL;
52     return Handle;
53 }
54 
55 BOOLEAN
56 NTAPI
DbgkpSuspendProcess(VOID)57 DbgkpSuspendProcess(VOID)
58 {
59     PAGED_CODE();
60 
61     /* Make sure this isn't a deleted process */
62     if (!PsGetCurrentProcess()->ProcessDelete)
63     {
64         /* Freeze all the threads */
65         KeFreezeAllThreads();
66         return TRUE;
67     }
68     else
69     {
70         /* No suspend was done */
71         return FALSE;
72     }
73 }
74 
75 VOID
76 NTAPI
DbgkpResumeProcess(VOID)77 DbgkpResumeProcess(VOID)
78 {
79     PAGED_CODE();
80 
81     /* Thaw all the threads */
82     KeThawAllThreads();
83 }
84 
85 VOID
86 NTAPI
DbgkCreateThread(IN PETHREAD Thread,IN PVOID StartAddress)87 DbgkCreateThread(IN PETHREAD Thread,
88                  IN PVOID StartAddress)
89 {
90     PEPROCESS Process = PsGetCurrentProcess();
91     ULONG ProcessFlags;
92     IMAGE_INFO ImageInfo;
93     PIMAGE_NT_HEADERS NtHeader;
94     POBJECT_NAME_INFORMATION ModuleName;
95     UNICODE_STRING NtDllName;
96     NTSTATUS Status;
97     PVOID DebugPort;
98     DBGKM_MSG ApiMessage;
99     PDBGKM_CREATE_THREAD CreateThread = &ApiMessage.CreateThread;
100     PDBGKM_CREATE_PROCESS CreateProcess = &ApiMessage.CreateProcess;
101     PDBGKM_LOAD_DLL LoadDll = &ApiMessage.LoadDll;
102     OBJECT_ATTRIBUTES ObjectAttributes;
103     IO_STATUS_BLOCK IoStatusBlock;
104     PTEB Teb;
105     PAGED_CODE();
106 
107     /* Sanity check */
108     ASSERT(Thread == PsGetCurrentThread());
109 
110     /* Try ORing in the create reported and image notify flags */
111     ProcessFlags = PspSetProcessFlag(Process,
112                                      PSF_CREATE_REPORTED_BIT |
113                                      PSF_IMAGE_NOTIFY_DONE_BIT);
114 
115     /* Check if we were the first to set them or if another thread raced us */
116     if (!(ProcessFlags & PSF_IMAGE_NOTIFY_DONE_BIT) && (PsImageNotifyEnabled))
117     {
118         /* It hasn't.. set up the image info for the process */
119         ImageInfo.Properties = 0;
120         ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
121         ImageInfo.ImageBase = Process->SectionBaseAddress;
122         ImageInfo.ImageSize = 0;
123         ImageInfo.ImageSelector = 0;
124         ImageInfo.ImageSectionNumber = 0;
125 
126         /* Get the NT Headers */
127         NtHeader = RtlImageNtHeader(Process->SectionBaseAddress);
128         if (NtHeader)
129         {
130             /* Set image size */
131             ImageInfo.ImageSize = NtHeader->OptionalHeader.SizeOfImage;
132         }
133 
134         /* Get the image name */
135         Status = MmGetFileNameForSection(Process->SectionObject, &ModuleName);
136         if (NT_SUCCESS(Status))
137         {
138             /* Call the notify routines and free the name */
139             PspRunLoadImageNotifyRoutines(&ModuleName->Name,
140                                           Process->UniqueProcessId,
141                                           &ImageInfo);
142             ExFreePool(ModuleName);
143         }
144         else
145         {
146             /* Call the notify routines */
147             PspRunLoadImageNotifyRoutines(NULL,
148                                           Process->UniqueProcessId,
149                                           &ImageInfo);
150         }
151 
152         /* Setup the info for ntdll.dll */
153         ImageInfo.Properties = 0;
154         ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
155         ImageInfo.ImageBase = PspSystemDllBase;
156         ImageInfo.ImageSize = 0;
157         ImageInfo.ImageSelector = 0;
158         ImageInfo.ImageSectionNumber = 0;
159 
160         /* Get the NT Headers */
161         NtHeader = RtlImageNtHeader(PspSystemDllBase);
162         if (NtHeader)
163         {
164             /* Set image size */
165             ImageInfo.ImageSize = NtHeader->OptionalHeader.SizeOfImage;
166         }
167 
168         /* Call the notify routines */
169         RtlInitUnicodeString(&NtDllName,
170                              L"\\SystemRoot\\System32\\ntdll.dll");
171         PspRunLoadImageNotifyRoutines(&NtDllName,
172                                       Process->UniqueProcessId,
173                                       &ImageInfo);
174     }
175 
176     /* Fail if we have no port */
177     DebugPort = Process->DebugPort;
178     if (!DebugPort) return;
179 
180     /* Check if create was not already reported */
181     if (!(ProcessFlags & PSF_CREATE_REPORTED_BIT))
182     {
183         /* Setup the information structure for the new thread */
184         CreateProcess->InitialThread.SubSystemKey = 0;
185         CreateProcess->InitialThread.StartAddress = NULL;
186 
187         /* And for the new process */
188         CreateProcess->SubSystemKey = 0;
189         CreateProcess->FileHandle = DbgkpSectionToFileHandle(Process->
190                                                              SectionObject);
191         CreateProcess->BaseOfImage = Process->SectionBaseAddress;
192         CreateProcess->DebugInfoFileOffset = 0;
193         CreateProcess->DebugInfoSize = 0;
194 
195         /* Get the NT Header */
196         NtHeader = RtlImageNtHeader(Process->SectionBaseAddress);
197         if (NtHeader)
198         {
199             /* Fill out data from the header */
200             CreateProcess->InitialThread.StartAddress =
201                 (PVOID)((ULONG_PTR)NtHeader->OptionalHeader.ImageBase +
202                         NtHeader->OptionalHeader.AddressOfEntryPoint);
203             CreateProcess->DebugInfoFileOffset = NtHeader->FileHeader.
204                                                  PointerToSymbolTable;
205             CreateProcess->DebugInfoSize = NtHeader->FileHeader.
206                                            NumberOfSymbols;
207         }
208 
209         /* Setup the API Message */
210         ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
211                                  (8 + sizeof(DBGKM_CREATE_PROCESS));
212         ApiMessage.h.u2.ZeroInit = 0;
213         ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
214         ApiMessage.ApiNumber = DbgKmCreateProcessApi;
215 
216         /* Send the message */
217         DbgkpSendApiMessage(&ApiMessage, FALSE);
218 
219         /* Close the handle */
220         ObCloseHandle(CreateProcess->FileHandle, KernelMode);
221 
222         /* Setup the parameters */
223         LoadDll->BaseOfDll = PspSystemDllBase;
224         LoadDll->DebugInfoFileOffset = 0;
225         LoadDll->DebugInfoSize = 0;
226         LoadDll->NamePointer = NULL;
227 
228         /* Get the NT Headers */
229         NtHeader = RtlImageNtHeader(PspSystemDllBase);
230         if (NtHeader)
231         {
232             /* Fill out debug information */
233             LoadDll->DebugInfoFileOffset = NtHeader->
234                                            FileHeader.PointerToSymbolTable;
235             LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols;
236         }
237 
238         /* Get the TEB */
239         Teb = Thread->Tcb.Teb;
240         if (Teb)
241         {
242             /* Copy the system library name and link to it */
243             wcsncpy(Teb->StaticUnicodeBuffer,
244                     L"ntdll.dll",
245                     sizeof(Teb->StaticUnicodeBuffer) / sizeof(WCHAR));
246             Teb->NtTib.ArbitraryUserPointer = Teb->StaticUnicodeBuffer;
247 
248             /* Return it in the debug event as well */
249             LoadDll->NamePointer = &Teb->NtTib.ArbitraryUserPointer;
250         }
251 
252         /* Get a handle */
253         InitializeObjectAttributes(&ObjectAttributes,
254                                    &PsNtDllPathName,
255                                    OBJ_CASE_INSENSITIVE |
256                                    OBJ_KERNEL_HANDLE |
257                                    OBJ_FORCE_ACCESS_CHECK,
258                                    NULL,
259                                    NULL);
260         Status = ZwOpenFile(&LoadDll->FileHandle,
261                             GENERIC_READ | SYNCHRONIZE,
262                             &ObjectAttributes,
263                             &IoStatusBlock,
264                             FILE_SHARE_DELETE |
265                             FILE_SHARE_READ |
266                             FILE_SHARE_WRITE,
267                             FILE_SYNCHRONOUS_IO_NONALERT);
268         if (NT_SUCCESS(Status))
269         {
270             /* Setup the API Message */
271             ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
272                                      (8 + sizeof(DBGKM_LOAD_DLL));
273             ApiMessage.h.u2.ZeroInit = 0;
274             ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
275             ApiMessage.ApiNumber = DbgKmLoadDllApi;
276 
277             /* Send the message */
278             DbgkpSendApiMessage(&ApiMessage, TRUE);
279 
280             /* Close the handle */
281             ObCloseHandle(LoadDll->FileHandle, KernelMode);
282         }
283     }
284     else
285     {
286         /* Otherwise, do it just for the thread */
287         CreateThread->SubSystemKey = 0;
288         CreateThread->StartAddress = StartAddress;
289 
290         /* Setup the API Message */
291         ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
292                                  (8 + sizeof(DBGKM_CREATE_THREAD));
293         ApiMessage.h.u2.ZeroInit = 0;
294         ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
295         ApiMessage.ApiNumber = DbgKmCreateThreadApi;
296 
297         /* Send the message */
298         DbgkpSendApiMessage(&ApiMessage, TRUE);
299     }
300 }
301 
302 VOID
303 NTAPI
DbgkExitProcess(IN NTSTATUS ExitStatus)304 DbgkExitProcess(IN NTSTATUS ExitStatus)
305 {
306     DBGKM_MSG ApiMessage;
307     PDBGKM_EXIT_PROCESS ExitProcess = &ApiMessage.ExitProcess;
308     PEPROCESS Process = PsGetCurrentProcess();
309     PETHREAD Thread = PsGetCurrentThread();
310     PAGED_CODE();
311 
312     /* Check if this thread is hidden, doesn't have a debug port, or died */
313     if ((Thread->HideFromDebugger) ||
314         !(Process->DebugPort) ||
315         (Thread->DeadThread))
316     {
317         /* Don't notify the debugger */
318         return;
319     }
320 
321     /* Set the exit status */
322     ExitProcess->ExitStatus = ExitStatus;
323 
324     /* Setup the API Message */
325     ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
326                              (8 + sizeof(DBGKM_EXIT_PROCESS));
327     ApiMessage.h.u2.ZeroInit = 0;
328     ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
329     ApiMessage.ApiNumber = DbgKmExitProcessApi;
330 
331     /* Set the current exit time */
332     KeQuerySystemTime(&Process->ExitTime);
333 
334     /* Send the message */
335     DbgkpSendApiMessage(&ApiMessage, FALSE);
336 }
337 
338 VOID
339 NTAPI
DbgkExitThread(IN NTSTATUS ExitStatus)340 DbgkExitThread(IN NTSTATUS ExitStatus)
341 {
342     DBGKM_MSG ApiMessage;
343     PDBGKM_EXIT_THREAD ExitThread = &ApiMessage.ExitThread;
344     PEPROCESS Process = PsGetCurrentProcess();
345     PETHREAD Thread = PsGetCurrentThread();
346     BOOLEAN Suspended;
347     PAGED_CODE();
348 
349     /* Check if this thread is hidden, doesn't have a debug port, or died */
350     if ((Thread->HideFromDebugger) ||
351         !(Process->DebugPort) ||
352         (Thread->DeadThread))
353     {
354         /* Don't notify the debugger */
355         return;
356     }
357 
358     /* Set the exit status */
359     ExitThread->ExitStatus = ExitStatus;
360 
361     /* Setup the API Message */
362     ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
363                              (8 + sizeof(DBGKM_EXIT_THREAD));
364     ApiMessage.h.u2.ZeroInit = 0;
365     ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
366     ApiMessage.ApiNumber = DbgKmExitThreadApi;
367 
368     /* Suspend the process */
369     Suspended = DbgkpSuspendProcess();
370 
371     /* Send the message */
372     DbgkpSendApiMessage(&ApiMessage, FALSE);
373 
374     /* Resume the process if needed */
375     if (Suspended) DbgkpResumeProcess();
376 }
377 
378 VOID
379 NTAPI
DbgkMapViewOfSection(IN PVOID Section,IN PVOID BaseAddress,IN ULONG SectionOffset,IN ULONG_PTR ViewSize)380 DbgkMapViewOfSection(IN PVOID Section,
381                      IN PVOID BaseAddress,
382                      IN ULONG SectionOffset,
383                      IN ULONG_PTR ViewSize)
384 {
385     DBGKM_MSG ApiMessage;
386     PDBGKM_LOAD_DLL LoadDll = &ApiMessage.LoadDll;
387     PEPROCESS Process = PsGetCurrentProcess();
388     PETHREAD Thread = PsGetCurrentThread();
389     PIMAGE_NT_HEADERS NtHeader;
390     PAGED_CODE();
391     DBGKTRACE(DBGK_PROCESS_DEBUG,
392               "Section: %p. Base: %p\n", Section, BaseAddress);
393 
394     /* Check if this thread is kernel, hidden or doesn't have a debug port */
395     if ((ExGetPreviousMode() == KernelMode) ||
396         (Thread->HideFromDebugger) ||
397         !(Process->DebugPort))
398     {
399         /* Don't notify the debugger */
400         return;
401     }
402 
403     /* Setup the parameters */
404     LoadDll->FileHandle = DbgkpSectionToFileHandle(Section);
405     LoadDll->BaseOfDll = BaseAddress;
406     LoadDll->DebugInfoFileOffset = 0;
407     LoadDll->DebugInfoSize = 0;
408     LoadDll->NamePointer = &NtCurrentTeb()->NtTib.ArbitraryUserPointer;
409 
410     /* Get the NT Headers */
411     NtHeader = RtlImageNtHeader(BaseAddress);
412     if (NtHeader)
413     {
414         /* Fill out debug information */
415         LoadDll->DebugInfoFileOffset = NtHeader->FileHeader.
416                                        PointerToSymbolTable;
417         LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols;
418     }
419 
420     /* Setup the API Message */
421     ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
422                              (8 + sizeof(DBGKM_LOAD_DLL));
423     ApiMessage.h.u2.ZeroInit = 0;
424     ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
425     ApiMessage.ApiNumber = DbgKmLoadDllApi;
426 
427     /* Send the message */
428     DbgkpSendApiMessage(&ApiMessage, TRUE);
429 
430     /* Close the handle */
431     ObCloseHandle(LoadDll->FileHandle, KernelMode);
432 }
433 
434 VOID
435 NTAPI
DbgkUnMapViewOfSection(IN PVOID BaseAddress)436 DbgkUnMapViewOfSection(IN PVOID BaseAddress)
437 {
438     DBGKM_MSG ApiMessage;
439     PDBGKM_UNLOAD_DLL UnloadDll = &ApiMessage.UnloadDll;
440     PEPROCESS Process = PsGetCurrentProcess();
441     PETHREAD Thread = PsGetCurrentThread();
442     PAGED_CODE();
443 
444     /* Check if this thread is kernel, hidden or doesn't have a debug port */
445     if ((ExGetPreviousMode() == KernelMode) ||
446         (Thread->HideFromDebugger) ||
447         !(Process->DebugPort))
448     {
449         /* Don't notify the debugger */
450         return;
451     }
452 
453     /* Set the DLL Base */
454     UnloadDll->BaseAddress = BaseAddress;
455 
456     /* Setup the API Message */
457     ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
458                              (8 + sizeof(DBGKM_UNLOAD_DLL));
459     ApiMessage.h.u2.ZeroInit = 0;
460     ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
461     ApiMessage.ApiNumber = DbgKmUnloadDllApi;
462 
463     /* Send the message */
464     DbgkpSendApiMessage(&ApiMessage, TRUE);
465 }
466