2285c95a955657fd549768af0e219f71d1f2460f
[reactos.git] / reactos / ntoskrnl / dbgk / dbgkutil.c
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
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
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
77 DbgkpResumeProcess(VOID)
78 {
79 PAGED_CODE();
80
81 /* Thaw all the threads */
82 KeThawAllThreads();
83 }
84
85 VOID
86 NTAPI
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 = LPC_DEBUG_EVENT;
213 ApiMessage.ApiNumber = DbgKmCreateProcessApi;
214
215 /* Send the message */
216 DbgkpSendApiMessage(&ApiMessage, FALSE);
217
218 /* Close the handle */
219 ObCloseHandle(CreateProcess->FileHandle, KernelMode);
220
221 /* Setup the parameters */
222 LoadDll->BaseOfDll = PspSystemDllBase;
223 LoadDll->DebugInfoFileOffset = 0;
224 LoadDll->DebugInfoSize = 0;
225 LoadDll->NamePointer = NULL;
226
227 /* Get the NT Headers */
228 NtHeader = RtlImageNtHeader(PspSystemDllBase);
229 if (NtHeader)
230 {
231 /* Fill out debug information */
232 LoadDll->DebugInfoFileOffset = NtHeader->
233 FileHeader.PointerToSymbolTable;
234 LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols;
235 }
236
237 /* Get the TEB */
238 Teb = Thread->Tcb.Teb;
239 if (Teb)
240 {
241 /* Copy the system library name and link to it */
242 wcsncpy(Teb->StaticUnicodeBuffer,
243 L"ntdll.dll",
244 sizeof(Teb->StaticUnicodeBuffer) / sizeof(WCHAR));
245 Teb->Tib.ArbitraryUserPointer = Teb->StaticUnicodeBuffer;
246
247 /* Return it in the debug event as well */
248 LoadDll->NamePointer = &Teb->Tib.ArbitraryUserPointer;
249 }
250
251 /* Get a handle */
252 InitializeObjectAttributes(&ObjectAttributes,
253 &PsNtDllPathName,
254 OBJ_CASE_INSENSITIVE |
255 OBJ_KERNEL_HANDLE |
256 OBJ_FORCE_ACCESS_CHECK,
257 NULL,
258 NULL);
259 Status = ZwOpenFile(&LoadDll->FileHandle,
260 GENERIC_READ | SYNCHRONIZE,
261 &ObjectAttributes,
262 &IoStatusBlock,
263 FILE_SHARE_DELETE |
264 FILE_SHARE_READ |
265 FILE_SHARE_WRITE,
266 FILE_SYNCHRONOUS_IO_NONALERT);
267 if (NT_SUCCESS(Status))
268 {
269 /* Setup the API Message */
270 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
271 (8 + sizeof(DBGKM_LOAD_DLL));
272 ApiMessage.h.u2.ZeroInit = LPC_DEBUG_EVENT;
273 ApiMessage.ApiNumber = DbgKmLoadDllApi;
274
275 /* Send the message */
276 DbgkpSendApiMessage(&ApiMessage, TRUE);
277
278 /* Close the handle */
279 ObCloseHandle(LoadDll->FileHandle, KernelMode);
280 }
281 }
282 else
283 {
284 /* Otherwise, do it just for the thread */
285 CreateThread->SubSystemKey = 0;
286 CreateThread->StartAddress = StartAddress;
287
288 /* Setup the API Message */
289 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
290 (8 + sizeof(DBGKM_CREATE_THREAD));
291 ApiMessage.h.u2.ZeroInit = LPC_DEBUG_EVENT;
292 ApiMessage.ApiNumber = DbgKmCreateThreadApi;
293
294 /* Send the message */
295 DbgkpSendApiMessage(&ApiMessage, TRUE);
296 }
297 }
298
299 VOID
300 NTAPI
301 DbgkExitProcess(IN NTSTATUS ExitStatus)
302 {
303 DBGKM_MSG ApiMessage;
304 PDBGKM_EXIT_PROCESS ExitProcess = &ApiMessage.ExitProcess;
305 PEPROCESS Process = PsGetCurrentProcess();
306 PETHREAD Thread = PsGetCurrentThread();
307 PAGED_CODE();
308
309 /* Check if this thread is hidden, doesn't have a debug port, or died */
310 if ((Thread->HideFromDebugger) ||
311 !(Process->DebugPort) ||
312 (Thread->DeadThread))
313 {
314 /* Don't notify the debugger */
315 return;
316 }
317
318 /* Set the exit status */
319 ExitProcess->ExitStatus = ExitStatus;
320
321 /* Setup the API Message */
322 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
323 (8 + sizeof(DBGKM_EXIT_PROCESS));
324 ApiMessage.h.u2.ZeroInit = LPC_DEBUG_EVENT;
325 ApiMessage.ApiNumber = DbgKmExitProcessApi;
326
327 /* Set the current exit time */
328 KeQuerySystemTime(&Process->ExitTime);
329
330 /* Send the message */
331 DbgkpSendApiMessage(&ApiMessage, FALSE);
332 }
333
334 VOID
335 NTAPI
336 DbgkExitThread(IN NTSTATUS ExitStatus)
337 {
338 DBGKM_MSG ApiMessage;
339 PDBGKM_EXIT_THREAD ExitThread = &ApiMessage.ExitThread;
340 PEPROCESS Process = PsGetCurrentProcess();
341 PETHREAD Thread = PsGetCurrentThread();
342 BOOLEAN Suspended;
343 PAGED_CODE();
344
345 /* Check if this thread is hidden, doesn't have a debug port, or died */
346 if ((Thread->HideFromDebugger) ||
347 !(Process->DebugPort) ||
348 (Thread->DeadThread))
349 {
350 /* Don't notify the debugger */
351 return;
352 }
353
354 /* Set the exit status */
355 ExitThread->ExitStatus = ExitStatus;
356
357 /* Setup the API Message */
358 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
359 (8 + sizeof(DBGKM_EXIT_THREAD));
360 ApiMessage.h.u2.ZeroInit = LPC_DEBUG_EVENT;
361 ApiMessage.ApiNumber = DbgKmExitThreadApi;
362
363 /* Suspend the process */
364 Suspended = DbgkpSuspendProcess();
365
366 /* Send the message */
367 DbgkpSendApiMessage(&ApiMessage, FALSE);
368
369 /* Resume the process if needed */
370 if (Suspended) DbgkpResumeProcess();
371 }
372
373 VOID
374 NTAPI
375 DbgkMapViewOfSection(IN PVOID Section,
376 IN PVOID BaseAddress,
377 IN ULONG SectionOffset,
378 IN ULONG_PTR ViewSize)
379 {
380 DBGKM_MSG ApiMessage;
381 PDBGKM_LOAD_DLL LoadDll = &ApiMessage.LoadDll;
382 PEPROCESS Process = PsGetCurrentProcess();
383 PETHREAD Thread = PsGetCurrentThread();
384 PIMAGE_NT_HEADERS NtHeader;
385 PAGED_CODE();
386 DBGKTRACE(DBGK_PROCESS_DEBUG,
387 "Section: %p. Base: %p\n", Section, BaseAddress);
388
389 /* Check if this thread is kernel, hidden or doesn't have a debug port */
390 if ((ExGetPreviousMode() == KernelMode) ||
391 (Thread->HideFromDebugger) ||
392 !(Process->DebugPort))
393 {
394 /* Don't notify the debugger */
395 return;
396 }
397
398 /* Setup the parameters */
399 LoadDll->FileHandle = DbgkpSectionToFileHandle(Section);
400 LoadDll->BaseOfDll = BaseAddress;
401 LoadDll->DebugInfoFileOffset = 0;
402 LoadDll->DebugInfoSize = 0;
403
404 /* Get the NT Headers */
405 NtHeader = RtlImageNtHeader(BaseAddress);
406 if (NtHeader)
407 {
408 /* Fill out debug information */
409 LoadDll->DebugInfoFileOffset = NtHeader->FileHeader.
410 PointerToSymbolTable;
411 LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols;
412 }
413
414 /* Setup the API Message */
415 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
416 (8 + sizeof(DBGKM_LOAD_DLL));
417 ApiMessage.h.u2.ZeroInit = LPC_DEBUG_EVENT;
418 ApiMessage.ApiNumber = DbgKmLoadDllApi;
419
420 /* Send the message */
421 DbgkpSendApiMessage(&ApiMessage, TRUE);
422
423 /* Close the handle */
424 ObCloseHandle(LoadDll->FileHandle, KernelMode);
425 }
426
427 VOID
428 NTAPI
429 DbgkUnMapViewOfSection(IN PVOID BaseAddress)
430 {
431 DBGKM_MSG ApiMessage;
432 PDBGKM_UNLOAD_DLL UnloadDll = &ApiMessage.UnloadDll;
433 PEPROCESS Process = PsGetCurrentProcess();
434 PETHREAD Thread = PsGetCurrentThread();
435 PAGED_CODE();
436
437 /* Check if this thread is kernel, hidden or doesn't have a debug port */
438 if ((ExGetPreviousMode() == KernelMode) ||
439 (Thread->HideFromDebugger) ||
440 !(Process->DebugPort))
441 {
442 /* Don't notify the debugger */
443 return;
444 }
445
446 /* Set the DLL Base */
447 UnloadDll->BaseAddress = BaseAddress;
448
449 /* Setup the API Message */
450 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
451 (8 + sizeof(DBGKM_UNLOAD_DLL));
452 ApiMessage.h.u2.ZeroInit = LPC_DEBUG_EVENT;
453 ApiMessage.ApiNumber = DbgKmUnloadDllApi;
454
455 /* Send the message */
456 DbgkpSendApiMessage(&ApiMessage, TRUE);
457 }