* Sync up to trunk head (r65394).
[reactos.git] / 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 = 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
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
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
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
409 /* Get the NT Headers */
410 NtHeader = RtlImageNtHeader(BaseAddress);
411 if (NtHeader)
412 {
413 /* Fill out debug information */
414 LoadDll->DebugInfoFileOffset = NtHeader->FileHeader.
415 PointerToSymbolTable;
416 LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols;
417 }
418
419 /* Setup the API Message */
420 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
421 (8 + sizeof(DBGKM_LOAD_DLL));
422 ApiMessage.h.u2.ZeroInit = 0;
423 ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
424 ApiMessage.ApiNumber = DbgKmLoadDllApi;
425
426 /* Send the message */
427 DbgkpSendApiMessage(&ApiMessage, TRUE);
428
429 /* Close the handle */
430 ObCloseHandle(LoadDll->FileHandle, KernelMode);
431 }
432
433 VOID
434 NTAPI
435 DbgkUnMapViewOfSection(IN PVOID BaseAddress)
436 {
437 DBGKM_MSG ApiMessage;
438 PDBGKM_UNLOAD_DLL UnloadDll = &ApiMessage.UnloadDll;
439 PEPROCESS Process = PsGetCurrentProcess();
440 PETHREAD Thread = PsGetCurrentThread();
441 PAGED_CODE();
442
443 /* Check if this thread is kernel, hidden or doesn't have a debug port */
444 if ((ExGetPreviousMode() == KernelMode) ||
445 (Thread->HideFromDebugger) ||
446 !(Process->DebugPort))
447 {
448 /* Don't notify the debugger */
449 return;
450 }
451
452 /* Set the DLL Base */
453 UnloadDll->BaseAddress = BaseAddress;
454
455 /* Setup the API Message */
456 ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
457 (8 + sizeof(DBGKM_UNLOAD_DLL));
458 ApiMessage.h.u2.ZeroInit = 0;
459 ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
460 ApiMessage.ApiNumber = DbgKmUnloadDllApi;
461
462 /* Send the message */
463 DbgkpSendApiMessage(&ApiMessage, TRUE);
464 }