3d4778bc63abe17e0d516e070ddb4732b8ba89b5
[reactos.git] / ntoskrnl / kdbg / kdb_symbols.cmake.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/dbg/kdb_symbols.c
5 * PURPOSE: Getting symbol information...
6 *
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Colin Finck (colin@reactos.org)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include "../cache/section/newmm.h"
17 #include <debug.h>
18
19 /* GLOBALS ******************************************************************/
20
21 #define CURRENT_PROCESS ((HANDLE)~0)
22
23 typedef struct _IMAGE_SYMBOL_INFO_CACHE
24 {
25 LIST_ENTRY ListEntry;
26 ULONG RefCount;
27 UNICODE_STRING FileName;
28 PROSSYM_INFO RosSymInfo;
29 }
30 IMAGE_SYMBOL_INFO_CACHE, *PIMAGE_SYMBOL_INFO_CACHE;
31
32 typedef struct _ROSSYM_KM_OWN_CONTEXT {
33 LARGE_INTEGER FileOffset;
34 PFILE_OBJECT FileObject;
35 } ROSSYM_KM_OWN_CONTEXT, *PROSSYM_KM_OWN_CONTEXT;
36
37 static BOOLEAN LoadSymbols;
38 static LIST_ENTRY SymbolFileListHead;
39 static KSPIN_LOCK SymbolFileListLock;
40 static PROSSYM_INFO KdbpRosSymInfo;
41 static ULONG_PTR KdbpImageBase;
42 BOOLEAN KdbpSymbolsInitialized = FALSE;
43
44 /* FUNCTIONS ****************************************************************/
45
46 static BOOLEAN
47 KdbpSeekSymFile(PVOID FileContext, ULONG_PTR Target)
48 {
49 PROSSYM_KM_OWN_CONTEXT Context = (PROSSYM_KM_OWN_CONTEXT)FileContext;
50 Context->FileOffset.QuadPart = Target;
51 return TRUE;
52 }
53
54 static BOOLEAN
55 KdbpReadSymFile(PVOID FileContext, PVOID Buffer, ULONG Length)
56 {
57 PROSSYM_KM_OWN_CONTEXT Context = (PROSSYM_KM_OWN_CONTEXT)FileContext;
58 IO_STATUS_BLOCK Iosb;
59 NTSTATUS Status = MiSimpleRead
60 (Context->FileObject,
61 &Context->FileOffset,
62 Buffer,
63 Length,
64 FALSE,
65 &Iosb);
66 return NT_SUCCESS(Status);
67 }
68
69 static PROSSYM_KM_OWN_CONTEXT
70 KdbpCaptureFileForSymbols(PFILE_OBJECT FileObject)
71 {
72 PROSSYM_KM_OWN_CONTEXT Context = ExAllocatePool(NonPagedPool, sizeof(*Context));
73 if (!Context) return NULL;
74 ObReferenceObject(FileObject);
75 Context->FileOffset.QuadPart = 0;
76 Context->FileObject = FileObject;
77 return Context;
78 }
79
80 static VOID
81 KdbpReleaseFileForSymbols(PROSSYM_KM_OWN_CONTEXT Context)
82 {
83 ObDereferenceObject(Context->FileObject);
84 ExFreePool(Context);
85 }
86
87 static BOOLEAN
88 KdbpSymSearchModuleList(
89 IN PLIST_ENTRY current_entry,
90 IN PLIST_ENTRY end_entry,
91 IN PLONG Count,
92 IN PVOID Address,
93 IN LPCWSTR Name,
94 IN INT Index,
95 OUT PLDR_DATA_TABLE_ENTRY* pLdrEntry)
96 {
97 while (current_entry && current_entry != end_entry)
98 {
99 *pLdrEntry = CONTAINING_RECORD(current_entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
100
101 if ((Address && Address >= (PVOID)(*pLdrEntry)->DllBase && Address < (PVOID)((ULONG_PTR)(*pLdrEntry)->DllBase + (*pLdrEntry)->SizeOfImage)) ||
102 (Name && !_wcsnicmp((*pLdrEntry)->BaseDllName.Buffer, Name, (*pLdrEntry)->BaseDllName.Length / sizeof(WCHAR))) ||
103 (Index >= 0 && (*Count)++ == Index))
104 {
105 return TRUE;
106 }
107
108 current_entry = current_entry->Flink;
109 }
110
111 return FALSE;
112 }
113
114 /*! \brief Find a module...
115 *
116 * \param Address If \a Address is not NULL the module containing \a Address
117 * is searched.
118 * \param Name If \a Name is not NULL the module named \a Name will be
119 * searched.
120 * \param Index If \a Index is >= 0 the Index'th module will be returned.
121 * \param pLdrEntry Pointer to a PLDR_DATA_TABLE_ENTRY which is filled.
122 *
123 * \retval TRUE Module was found, \a pLdrEntry was filled.
124 * \retval FALSE No module was found.
125 */
126 BOOLEAN
127 KdbpSymFindModule(
128 IN PVOID Address OPTIONAL,
129 IN LPCWSTR Name OPTIONAL,
130 IN INT Index OPTIONAL,
131 OUT PLDR_DATA_TABLE_ENTRY* pLdrEntry)
132 {
133 LONG Count = 0;
134 PEPROCESS CurrentProcess;
135
136 /* First try to look up the module in the kernel module list. */
137 if(KdbpSymSearchModuleList(PsLoadedModuleList.Flink,
138 &PsLoadedModuleList,
139 &Count,
140 Address,
141 Name,
142 Index,
143 pLdrEntry))
144 {
145 return TRUE;
146 }
147
148 /* That didn't succeed. Try the module list of the current process now. */
149 CurrentProcess = PsGetCurrentProcess();
150
151 if(!CurrentProcess || !CurrentProcess->Peb || !CurrentProcess->Peb->Ldr)
152 return FALSE;
153
154 return KdbpSymSearchModuleList(CurrentProcess->Peb->Ldr->InLoadOrderModuleList.Flink,
155 &CurrentProcess->Peb->Ldr->InLoadOrderModuleList,
156 &Count,
157 Address,
158 Name,
159 Index,
160 pLdrEntry);
161 }
162
163 /*! \brief Print address...
164 *
165 * Tries to lookup line number, file name and function name for the given
166 * address and prints it.
167 * If no such information is found the address is printed in the format
168 * <module: offset>, otherwise the format will be
169 * <module: offset (filename:linenumber (functionname))>
170 *
171 * \retval TRUE Module containing \a Address was found, \a Address was printed.
172 * \retval FALSE No module containing \a Address was found, nothing was printed.
173 */
174 BOOLEAN
175 KdbSymPrintAddress(
176 IN PVOID Address,
177 IN PKTRAP_FRAME Context)
178 {
179 int i;
180 PMEMORY_AREA MemoryArea = NULL;
181 PROS_SECTION_OBJECT SectionObject;
182 PLDR_DATA_TABLE_ENTRY LdrEntry;
183 PROSSYM_KM_OWN_CONTEXT FileContext;
184 ULONG_PTR RelativeAddress;
185 NTSTATUS Status;
186 ROSSYM_LINEINFO LineInfo = {0};
187
188 struct {
189 enum _ROSSYM_REGNAME regname;
190 size_t ctx_offset;
191 } regmap[] = {
192 { ROSSYM_X86_EDX, FIELD_OFFSET(KTRAP_FRAME, Edx) },
193 { ROSSYM_X86_EAX, FIELD_OFFSET(KTRAP_FRAME, Eax) },
194 { ROSSYM_X86_ECX, FIELD_OFFSET(KTRAP_FRAME, Ecx) },
195 { ROSSYM_X86_EBX, FIELD_OFFSET(KTRAP_FRAME, Ebx) },
196 { ROSSYM_X86_ESI, FIELD_OFFSET(KTRAP_FRAME, Esi) },
197 { ROSSYM_X86_EDI, FIELD_OFFSET(KTRAP_FRAME, Edi) },
198 { ROSSYM_X86_EBP, FIELD_OFFSET(KTRAP_FRAME, Ebp) },
199 { ROSSYM_X86_ESP, FIELD_OFFSET(KTRAP_FRAME, HardwareEsp) }
200 };
201
202 if (Context)
203 {
204 DPRINT("Has Context %x (EBP %x)\n", Context, Context->Ebp);
205 LineInfo.Flags = ROSSYM_LINEINFO_HAS_REGISTERS;
206
207 for (i = 0; i < sizeof(regmap) / sizeof(regmap[0]); i++) {
208 memcpy
209 (&LineInfo.Registers.Registers[regmap[i].regname],
210 ((PCHAR)Context)+regmap[i].ctx_offset,
211 sizeof(ULONG_PTR));
212 DPRINT("DWARF REG[%d] -> %x\n", regmap[i].regname, LineInfo.Registers.Registers[regmap[i].regname]);
213 }
214 }
215
216 if (!KdbpSymbolsInitialized || !KdbpSymFindModule(Address, NULL, -1, &LdrEntry))
217 return FALSE;
218
219 RelativeAddress = (ULONG_PTR)Address - (ULONG_PTR)LdrEntry->DllBase;
220 Status = KdbSymGetAddressInformation
221 (LdrEntry->PatchInformation,
222 RelativeAddress,
223 &LineInfo);
224
225 if (NT_SUCCESS(Status))
226 {
227 DbgPrint("<%wZ:%x (%s:%d (%s))>",
228 &LdrEntry->BaseDllName, RelativeAddress, LineInfo.FileName, LineInfo.LineNumber, LineInfo.FunctionName);
229 if (Context)
230 {
231 int i;
232 char *comma = "";
233 DbgPrint("(");
234 for (i = 0; i < LineInfo.NumParams; i++) {
235 DbgPrint
236 ("%s%s=%llx",
237 comma,
238 LineInfo.Parameters[i].ValueName,
239 LineInfo.Parameters[i].Value);
240 comma = ",";
241 }
242 DbgPrint(")");
243 }
244
245 return TRUE;
246 }
247 else if (Address < MmSystemRangeStart)
248 {
249 MemoryArea = MmLocateMemoryAreaByAddress(&PsGetCurrentProcess()->Vm, Address);
250 if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
251 {
252 goto end;
253 }
254 SectionObject = MemoryArea->Data.SectionData.Section;
255 if (!(SectionObject->AllocationAttributes & SEC_IMAGE)) goto end;
256 if (MemoryArea->StartingAddress != (PVOID)KdbpImageBase)
257 {
258 if (KdbpRosSymInfo)
259 {
260 RosSymDelete(KdbpRosSymInfo);
261 KdbpRosSymInfo = NULL;
262 KdbpImageBase = 0;
263 }
264
265 if ((FileContext = KdbpCaptureFileForSymbols(SectionObject->FileObject)))
266 {
267 if (RosSymCreateFromFile(FileContext, &KdbpRosSymInfo))
268 KdbpImageBase = (ULONG_PTR)MemoryArea->StartingAddress;
269
270 KdbpReleaseFileForSymbols(FileContext);
271 }
272 }
273
274 if (KdbpRosSymInfo)
275 {
276 RelativeAddress = (ULONG_PTR)Address - KdbpImageBase;
277 RosSymFreeInfo(&LineInfo);
278 Status = KdbSymGetAddressInformation
279 (KdbpRosSymInfo,
280 RelativeAddress,
281 &LineInfo);
282 if (NT_SUCCESS(Status))
283 {
284 DbgPrint
285 ("<%wZ:%x (%s:%d (%s))>",
286 &SectionObject->FileObject->FileName,
287 RelativeAddress,
288 LineInfo.FileName,
289 LineInfo.LineNumber,
290 LineInfo.FunctionName);
291
292 if (Context)
293 {
294 int i;
295 char *comma = "";
296 DbgPrint("(");
297 for (i = 0; i < LineInfo.NumParams; i++) {
298 DbgPrint
299 ("%s%s=%llx",
300 comma,
301 LineInfo.Parameters[i].ValueName,
302 LineInfo.Parameters[i].Value);
303 comma = ",";
304 }
305 DbgPrint(")");
306 }
307
308 return TRUE;
309 }
310 }
311 }
312
313 end:
314 DbgPrint("<%wZ:%x>", &LdrEntry->BaseDllName, RelativeAddress);
315
316 return TRUE;
317 }
318
319
320 /*! \brief Get information for an address (source file, line number,
321 * function name)
322 *
323 * \param SymbolInfo Pointer to ROSSYM_INFO.
324 * \param RelativeAddress Relative address to look up.
325 * \param LineNumber Pointer to an ULONG which is filled with the line
326 * number (can be NULL)
327 * \param FileName Pointer to an array of CHARs which gets filled with
328 * the filename (can be NULL)
329 * \param FunctionName Pointer to an array of CHARs which gets filled with
330 * the function name (can be NULL)
331 *
332 * \returns NTSTATUS error code.
333 * \retval STATUS_SUCCESS At least one of the requested informations was found.
334 * \retval STATUS_UNSUCCESSFUL None of the requested information was found.
335 */
336 NTSTATUS
337 KdbSymGetAddressInformation(
338 IN PROSSYM_INFO RosSymInfo,
339 IN ULONG_PTR RelativeAddress,
340 IN PROSSYM_LINEINFO LineInfo)
341 {
342 if (!KdbpSymbolsInitialized ||
343 !RosSymInfo ||
344 !RosSymGetAddressInformation(RosSymInfo, RelativeAddress, LineInfo))
345 {
346 return STATUS_UNSUCCESSFUL;
347 }
348
349 return STATUS_SUCCESS;
350 }
351
352 /*! \brief Find cached symbol file.
353 *
354 * Looks through the list of cached symbol files and tries to find an already
355 * loaded one.
356 *
357 * \param FileName FileName of the symbol file to look for.
358 *
359 * \returns A pointer to the cached symbol info.
360 * \retval NULL No cached info found.
361 *
362 * \sa KdbpSymAddCachedFile
363 */
364 PROSSYM_INFO
365 KdbpSymFindCachedFile(
366 IN PUNICODE_STRING FileName)
367 {
368 PIMAGE_SYMBOL_INFO_CACHE Current;
369 PLIST_ENTRY CurrentEntry;
370 KIRQL Irql;
371
372 KeAcquireSpinLock(&SymbolFileListLock, &Irql);
373
374 CurrentEntry = SymbolFileListHead.Flink;
375 while (CurrentEntry != (&SymbolFileListHead))
376 {
377 Current = CONTAINING_RECORD(CurrentEntry, IMAGE_SYMBOL_INFO_CACHE, ListEntry);
378
379 if (RtlEqualUnicodeString(&Current->FileName, FileName, TRUE))
380 {
381 Current->RefCount++;
382 KeReleaseSpinLock(&SymbolFileListLock, Irql);
383 DPRINT("Found cached file!\n");
384 return Current->RosSymInfo;
385 }
386
387 CurrentEntry = CurrentEntry->Flink;
388 }
389
390 KeReleaseSpinLock(&SymbolFileListLock, Irql);
391
392 DPRINT("Cached file not found!\n");
393 return NULL;
394 }
395
396 /*! \brief Add a symbol file to the cache.
397 *
398 * \param FileName Filename of the symbol file.
399 * \param RosSymInfo Pointer to the symbol info.
400 *
401 * \sa KdbpSymRemoveCachedFile
402 */
403 static VOID
404 KdbpSymAddCachedFile(
405 IN PUNICODE_STRING FileName,
406 IN PROSSYM_INFO RosSymInfo)
407 {
408 PIMAGE_SYMBOL_INFO_CACHE CacheEntry;
409
410 DPRINT("Adding symbol file: %wZ RosSymInfo = %p\n", FileName, RosSymInfo);
411
412 /* allocate entry */
413 CacheEntry = ExAllocatePoolWithTag(NonPagedPool, sizeof (IMAGE_SYMBOL_INFO_CACHE), TAG_KDBS);
414 ASSERT(CacheEntry);
415 RtlZeroMemory(CacheEntry, sizeof (IMAGE_SYMBOL_INFO_CACHE));
416
417 /* fill entry */
418 CacheEntry->FileName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
419 FileName->Length,
420 TAG_KDBS);
421 CacheEntry->FileName.MaximumLength = FileName->Length;
422 RtlCopyUnicodeString(&CacheEntry->FileName, FileName);
423 ASSERT(CacheEntry->FileName.Buffer);
424 CacheEntry->RefCount = 1;
425 CacheEntry->RosSymInfo = RosSymInfo;
426 InsertTailList(&SymbolFileListHead, &CacheEntry->ListEntry); /* FIXME: Lock list? */
427 }
428
429 /*! \brief Remove a symbol file (reference) from the cache.
430 *
431 * Tries to find a cache entry matching the given symbol info and decreases
432 * it's reference count. If the refcount is 0 after decreasing it the cache
433 * entry will be removed from the list and freed.
434 *
435 * \param RosSymInfo Pointer to the symbol info.
436 *
437 * \sa KdbpSymAddCachedFile
438 */
439 static VOID
440 KdbpSymRemoveCachedFile(
441 IN PROSSYM_INFO RosSymInfo)
442 {
443 PIMAGE_SYMBOL_INFO_CACHE Current;
444 PLIST_ENTRY CurrentEntry;
445 KIRQL Irql;
446
447 KeAcquireSpinLock(&SymbolFileListLock, &Irql);
448
449 CurrentEntry = SymbolFileListHead.Flink;
450 while (CurrentEntry != (&SymbolFileListHead))
451 {
452 Current = CONTAINING_RECORD(CurrentEntry, IMAGE_SYMBOL_INFO_CACHE, ListEntry);
453
454 if (Current->RosSymInfo == RosSymInfo) /* found */
455 {
456 ASSERT(Current->RefCount > 0);
457 Current->RefCount--;
458 if (Current->RefCount < 1)
459 {
460 RemoveEntryList(&Current->ListEntry);
461 RosSymDelete(Current->RosSymInfo);
462 ExFreePool(Current);
463 }
464
465 KeReleaseSpinLock(&SymbolFileListLock, Irql);
466 return;
467 }
468
469 CurrentEntry = CurrentEntry->Flink;
470 }
471
472 KeReleaseSpinLock(&SymbolFileListLock, Irql);
473 }
474
475 /*! \brief Loads a symbol file.
476 *
477 * \param FileName Filename of the symbol file to load.
478 * \param RosSymInfo Pointer to a ROSSYM_INFO which gets filled.
479 *
480 * \sa KdbpSymUnloadModuleSymbols
481 */
482 VOID
483 KdbpSymLoadModuleSymbols(
484 IN PUNICODE_STRING FileName,
485 OUT PROSSYM_INFO *RosSymInfo)
486 {
487 OBJECT_ATTRIBUTES ObjectAttributes;
488 HANDLE FileHandle;
489 NTSTATUS Status;
490 IO_STATUS_BLOCK IoStatusBlock;
491 PFILE_OBJECT FileObject;
492 PROSSYM_KM_OWN_CONTEXT FileContext;
493
494 /* Allow KDB to break on module load */
495 KdbModuleLoaded(FileName);
496
497 if (!LoadSymbols)
498 {
499 *RosSymInfo = NULL;
500 return;
501 }
502
503 /* Try to find cached (already loaded) symbol file */
504 *RosSymInfo = KdbpSymFindCachedFile(FileName);
505 if (*RosSymInfo)
506 {
507 DPRINT("Found cached symbol file %wZ\n", FileName);
508 return;
509 }
510
511 /* Open the file */
512 InitializeObjectAttributes(&ObjectAttributes,
513 FileName,
514 OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
515 NULL,
516 NULL);
517
518 DPRINT("Attempting to open image: %wZ\n", FileName);
519
520 Status = ZwOpenFile(&FileHandle,
521 FILE_READ_ACCESS,
522 &ObjectAttributes,
523 &IoStatusBlock,
524 FILE_SHARE_READ|FILE_SHARE_WRITE,
525 FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT);
526 if (!NT_SUCCESS(Status))
527 {
528 DPRINT("Could not open image file(%x): %wZ\n", Status, FileName);
529 return;
530 }
531
532 DPRINT("Loading symbols from %wZ...\n", FileName);
533
534 Status = ObReferenceObjectByHandle
535 (FileHandle,
536 FILE_READ_DATA|SYNCHRONIZE,
537 NULL,
538 KernelMode,
539 (PVOID*)&FileObject,
540 NULL);
541
542 if (!NT_SUCCESS(Status))
543 {
544 DPRINT("Could not get the file object\n");
545 ZwClose(FileHandle);
546 return;
547 }
548
549 if ((FileContext = KdbpCaptureFileForSymbols(FileObject)))
550 {
551 if (RosSymCreateFromFile(FileContext, RosSymInfo))
552 {
553 /* add file to cache */
554 int i;
555 UNICODE_STRING TruncatedName = *FileName;
556 for (i = (TruncatedName.Length / sizeof(WCHAR)) - 1; i >= 0; i--)
557 if (TruncatedName.Buffer[i] == '\\') {
558 TruncatedName.Buffer += i+1;
559 TruncatedName.Length -= (i+1)*sizeof(WCHAR);
560 TruncatedName.MaximumLength -= (i+1)*sizeof(WCHAR);
561 break;
562 }
563 KdbpSymAddCachedFile(&TruncatedName, *RosSymInfo);
564 DPRINT("Installed symbols: %wZ %p\n", &TruncatedName, *RosSymInfo);
565 }
566 KdbpReleaseFileForSymbols(FileContext);
567 }
568
569 ObDereferenceObject(FileObject);
570 ZwClose(FileHandle);
571 }
572
573 VOID
574 KdbSymProcessSymbols(
575 IN PLDR_DATA_TABLE_ENTRY LdrEntry)
576 {
577 if (!LoadSymbols)
578 {
579 LdrEntry->PatchInformation = NULL;
580 return;
581 }
582
583 /* Remove symbol info if it already exists */
584 if (LdrEntry->PatchInformation) {
585 KdbpSymRemoveCachedFile(LdrEntry->PatchInformation);
586 }
587
588 /* Error loading symbol info, try to load it from file */
589 KdbpSymLoadModuleSymbols(&LdrEntry->FullDllName,
590 (PROSSYM_INFO*)&LdrEntry->PatchInformation);
591
592 if (!LdrEntry->PatchInformation) {
593 // HACK: module dll names don't identify the real files
594 UNICODE_STRING SystemRoot;
595 UNICODE_STRING ModuleNameCopy;
596 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot\\system32\\Drivers\\");
597 ModuleNameCopy.Length = 0;
598 ModuleNameCopy.MaximumLength =
599 LdrEntry->BaseDllName.MaximumLength + SystemRoot.MaximumLength;
600 ModuleNameCopy.Buffer = ExAllocatePool(NonPagedPool, SystemRoot.MaximumLength + LdrEntry->BaseDllName.MaximumLength);
601 RtlCopyUnicodeString(&ModuleNameCopy, &SystemRoot);
602 RtlCopyMemory
603 (ModuleNameCopy.Buffer + ModuleNameCopy.Length / sizeof(WCHAR),
604 LdrEntry->BaseDllName.Buffer,
605 LdrEntry->BaseDllName.Length);
606 ModuleNameCopy.Length += LdrEntry->BaseDllName.Length;
607 KdbpSymLoadModuleSymbols(&ModuleNameCopy,
608 (PROSSYM_INFO*)&LdrEntry->PatchInformation);
609 if (!LdrEntry->PatchInformation) {
610 SystemRoot.Length -= strlen("Drivers\\") * sizeof(WCHAR);
611 RtlCopyUnicodeString(&ModuleNameCopy, &SystemRoot);
612 RtlCopyMemory
613 (ModuleNameCopy.Buffer + ModuleNameCopy.Length / sizeof(WCHAR),
614 LdrEntry->BaseDllName.Buffer,
615 LdrEntry->BaseDllName.Length);
616 ModuleNameCopy.Length += LdrEntry->BaseDllName.Length;
617 KdbpSymLoadModuleSymbols(&ModuleNameCopy,
618 (PROSSYM_INFO*)&LdrEntry->PatchInformation);
619 }
620 RtlFreeUnicodeString(&ModuleNameCopy);
621 }
622
623 /* It already added symbols to cache */
624 DPRINT("Installed symbols: %wZ@%p-%p %p\n",
625 &LdrEntry->BaseDllName,
626 LdrEntry->DllBase,
627 (PVOID)(LdrEntry->SizeOfImage + (ULONG_PTR)LdrEntry->DllBase),
628 LdrEntry->PatchInformation);
629 }
630
631 VOID
632 NTAPI
633 KdbDebugPrint(
634 PCH Message,
635 ULONG Length)
636 {
637 /* Nothing here */
638 }
639
640 typedef struct {
641 PMDL Mdl;
642 SIZE_T Size;
643 PVOID OriginalMapping;
644 } KdbpMallocHeader;
645
646 static PVOID KdbpSymAllocMem(ULONG_PTR Size)
647 {
648 KdbpMallocHeader *Hdr;
649 if (Size < PAGE_SIZE)
650 {
651 PVOID Result = ExAllocatePoolWithTag(NonPagedPool, Size + sizeof(KdbpMallocHeader), 'RSYM');
652 if (!Result) return NULL;
653 Hdr = (KdbpMallocHeader*)Result;
654 Hdr->Mdl = NULL;
655 Hdr->Size = Size;
656 return &Hdr[1];
657 }
658 else
659 {
660 PVOID Base = NULL;
661 SIZE_T RegionSize = Size + sizeof(KdbpMallocHeader);
662 NTSTATUS Status = NtAllocateVirtualMemory
663 (CURRENT_PROCESS, &Base, 0, &RegionSize, MEM_COMMIT, PAGE_READWRITE);
664 if (!NT_SUCCESS(Status)) return NULL;
665 Hdr = (KdbpMallocHeader*)Base;
666 Hdr->Mdl = IoAllocateMdl(Base, RegionSize, FALSE, FALSE, NULL);
667 if (!Hdr->Mdl) {
668 NtFreeVirtualMemory(CURRENT_PROCESS, &Base, &RegionSize, MEM_RELEASE);
669 return NULL;
670 }
671 Hdr->Size = RegionSize;
672 Hdr->OriginalMapping = Base;
673 MmProbeAndLockPages(Hdr->Mdl, KernelMode, IoModifyAccess);
674 KdbpMallocHeader *MappedHdr = (KdbpMallocHeader*)MmMapLockedPages(Hdr->Mdl, KernelMode);
675 if (!MappedHdr) {
676 MmUnlockPages(Hdr->Mdl);
677 IoFreeMdl(Hdr->Mdl);
678 NtFreeVirtualMemory(CURRENT_PROCESS, &Base, &RegionSize, MEM_RELEASE);
679 return NULL;
680 }
681 return &MappedHdr[1];
682 }
683 }
684
685 static VOID KdbpSymFreeMem(PVOID Area)
686 {
687 PCHAR HdrPtr = ((PCHAR)Area) - sizeof(KdbpMallocHeader);
688 KdbpMallocHeader *Hdr = (KdbpMallocHeader*)HdrPtr;
689 if (Hdr->Size < PAGE_SIZE)
690 {
691 ExFreePool(Hdr);
692 }
693 else
694 {
695 PMDL Mdl = Hdr->Mdl;
696 PVOID BaseAddress = Hdr->OriginalMapping;
697 SIZE_T RegionSize = Hdr->Size;
698 MmUnmapLockedPages(Hdr, Mdl);
699 MmUnlockPages(Mdl);
700 NtFreeVirtualMemory(CURRENT_PROCESS, &BaseAddress, &RegionSize, MEM_RELEASE);
701 IoFreeMdl(Mdl);
702 }
703 }
704
705 static BOOLEAN KdbpSymReadMem(PVOID FileContext, PVOID TargetDebug, PVOID SourceMem, ULONG Size)
706 {
707 return NT_SUCCESS(KdbpSafeReadMemory(TargetDebug, SourceMem, Size));
708 }
709
710 static ROSSYM_CALLBACKS KdbpRosSymCallbacks = {
711 KdbpSymAllocMem, KdbpSymFreeMem,
712 KdbpReadSymFile, KdbpSeekSymFile,
713 KdbpSymReadMem
714 };
715
716 /*! \brief Initializes the KDB symbols implementation.
717 *
718 * \param DispatchTable Pointer to the KD dispatch table
719 * \param BootPhase Phase of initialization
720 */
721 VOID
722 NTAPI
723 KdbInitialize(
724 PKD_DISPATCH_TABLE DispatchTable,
725 ULONG BootPhase)
726 {
727 PCHAR p1, p2;
728 SHORT Found = FALSE;
729 CHAR YesNo;
730 PLDR_DATA_TABLE_ENTRY LdrEntry;
731
732 DPRINT("KdbSymInit() BootPhase=%d\n", BootPhase);
733
734 LoadSymbols = FALSE;
735
736 #if DBG
737 /* Load symbols only if we have 96Mb of RAM or more */
738 if (MmNumberOfPhysicalPages >= 0x6000)
739 LoadSymbols = TRUE;
740 #endif
741
742 if (BootPhase == 0)
743 {
744 /* Write out the functions that we support for now */
745 DispatchTable->KdpInitRoutine = KdpKdbgInit;
746 DispatchTable->KdpPrintRoutine = KdbDebugPrint;
747
748 /* Register as a Provider */
749 InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
750
751 /* Perform actual initialization of symbol module */
752 //NtoskrnlModuleObject->PatchInformation = NULL;
753 //LdrHalModuleObject->PatchInformation = NULL;
754
755 InitializeListHead(&SymbolFileListHead);
756 KeInitializeSpinLock(&SymbolFileListLock);
757
758 /* Check the command line for /LOADSYMBOLS, /NOLOADSYMBOLS,
759 * /LOADSYMBOLS={YES|NO}, /NOLOADSYMBOLS={YES|NO} */
760 ASSERT(KeLoaderBlock);
761 p1 = KeLoaderBlock->LoadOptions;
762 while('\0' != *p1 && NULL != (p2 = strchr(p1, '/')))
763 {
764 p2++;
765 Found = 0;
766 if (0 == _strnicmp(p2, "LOADSYMBOLS", 11))
767 {
768 Found = +1;
769 p2 += 11;
770 }
771 else if (0 == _strnicmp(p2, "NOLOADSYMBOLS", 13))
772 {
773 Found = -1;
774 p2 += 13;
775 }
776 if (0 != Found)
777 {
778 while (isspace(*p2))
779 {
780 p2++;
781 }
782 if ('=' == *p2)
783 {
784 p2++;
785 while (isspace(*p2))
786 {
787 p2++;
788 }
789 YesNo = toupper(*p2);
790 if ('N' == YesNo || 'F' == YesNo || '0' == YesNo)
791 {
792 Found = -1 * Found;
793 }
794 }
795 LoadSymbols = (0 < Found);
796 }
797 p1 = p2;
798 }
799
800 RosSymInit(&KdbpRosSymCallbacks);
801 }
802 else if (BootPhase == 3)
803 {
804 /* Load symbols for NTOSKRNL.EXE.
805 It is always the first module in PsLoadedModuleList. KeLoaderBlock can't be used here as its content is just temporary. */
806 LdrEntry = CONTAINING_RECORD(PsLoadedModuleList.Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
807 KdbSymProcessSymbols(LdrEntry);
808
809 /* Also load them for HAL.DLL. */
810 LdrEntry = CONTAINING_RECORD(PsLoadedModuleList.Flink->Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
811 KdbSymProcessSymbols(LdrEntry);
812
813 KdbpSymbolsInitialized = TRUE;
814 }
815 }
816
817 /* EOF */