Cleanup isn't necessary after calling the driver in NtQueryDirectoryFile.
[reactos.git] / reactos / ntoskrnl / kdbg / kdb_symbols.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 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 typedef struct _IMAGE_SYMBOL_INFO_CACHE {
20 LIST_ENTRY ListEntry;
21 ULONG RefCount;
22 UNICODE_STRING FileName;
23 PROSSYM_INFO RosSymInfo;
24 } IMAGE_SYMBOL_INFO_CACHE, *PIMAGE_SYMBOL_INFO_CACHE;
25
26 static BOOLEAN LoadSymbols;
27 static LIST_ENTRY SymbolFileListHead;
28 static KSPIN_LOCK SymbolFileListLock;
29
30
31 /* FUNCTIONS ****************************************************************/
32
33 /*! \brief Find a user-mode module...
34 *
35 * \param Address If \a Address is not NULL the module containing \a Address
36 * is searched.
37 * \param Name If \a Name is not NULL the module named \a Name will be
38 * searched.
39 * \param Index If \a Index is >= 0 the Index'th module will be returned.
40 * \param pInfo Pointer to a KDB_MODULE_INFO which is filled.
41 *
42 * \retval TRUE Module was found, \a pInfo was filled.
43 * \retval FALSE No module was found.
44 *
45 * \sa KdbpSymFindModule
46 */
47 STATIC BOOLEAN
48 KdbpSymFindUserModule(IN PVOID Address OPTIONAL,
49 IN LPCWSTR Name OPTIONAL,
50 IN INT Index OPTIONAL,
51 OUT PKDB_MODULE_INFO pInfo)
52 {
53 PLIST_ENTRY current_entry;
54 PLDR_DATA_TABLE_ENTRY current;
55 PEPROCESS CurrentProcess;
56 PPEB Peb = NULL;
57 INT Count = 0;
58 INT Length;
59
60 CurrentProcess = PsGetCurrentProcess();
61 if (CurrentProcess != NULL)
62 {
63 Peb = CurrentProcess->Peb;
64 }
65
66 if (Peb == NULL || Peb->Ldr == NULL)
67 {
68 return FALSE;
69 }
70
71 current_entry = Peb->Ldr->InLoadOrderModuleList.Flink;
72
73 while (current_entry != &Peb->Ldr->InLoadOrderModuleList &&
74 current_entry != NULL)
75 {
76 current = CONTAINING_RECORD(current_entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
77 Length = min(current->BaseDllName.Length / sizeof(WCHAR), 255);
78 if ((Address != NULL && (Address >= (PVOID)current->DllBase &&
79 Address < (PVOID)((char *)current->DllBase + current->SizeOfImage))) ||
80 (Name != NULL && _wcsnicmp(current->BaseDllName.Buffer, Name, Length) == 0) ||
81 (Index >= 0 && Count++ == Index))
82 {
83 wcsncpy(pInfo->Name, current->BaseDllName.Buffer, Length);
84 pInfo->Name[Length] = L'\0';
85 pInfo->Base = (ULONG_PTR)current->DllBase;
86 pInfo->Size = current->SizeOfImage;
87 pInfo->RosSymInfo = current->PatchInformation;
88 return TRUE;
89 }
90 current_entry = current_entry->Flink;
91 }
92
93 return FALSE;
94 }
95
96 /*! \brief Find a kernel-mode module...
97 *
98 * Works like \a KdbpSymFindUserModule.
99 *
100 * \sa KdbpSymFindUserModule
101 */
102 STATIC BOOLEAN
103 KdbpSymFindModule(IN PVOID Address OPTIONAL,
104 IN LPCWSTR Name OPTIONAL,
105 IN INT Index OPTIONAL,
106 OUT PKDB_MODULE_INFO pInfo)
107 {
108 PLIST_ENTRY current_entry;
109 PLDR_DATA_TABLE_ENTRY current;
110 extern LIST_ENTRY ModuleListHead;
111 INT Count = 0;
112 INT Length;
113
114 current_entry = ModuleListHead.Flink;
115
116 while (current_entry != &ModuleListHead)
117 {
118 current = CONTAINING_RECORD(current_entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
119
120 Length = min(current->BaseDllName.Length / sizeof(WCHAR), 255);
121 if ((Address != NULL && (Address >= (PVOID)current->DllBase &&
122 Address < (PVOID)((ULONG_PTR)current->DllBase + current->SizeOfImage))) ||
123 (Name != NULL && _wcsnicmp(current->BaseDllName.Buffer, Name, Length) == 0) ||
124 (Index >= 0 && Count++ == Index))
125 {
126 wcsncpy(pInfo->Name, current->BaseDllName.Buffer, Length);
127 pInfo->Name[Length] = L'\0';
128 pInfo->Base = (ULONG_PTR)current->DllBase;
129 pInfo->Size = current->SizeOfImage;
130 pInfo->RosSymInfo = current->PatchInformation;
131 return TRUE;
132 }
133 current_entry = current_entry->Flink;
134 }
135
136 return KdbpSymFindUserModule(Address, Name, Index-Count, pInfo);
137 }
138
139 /*! \brief Find module by address...
140 *
141 * \param Address Any address inside the module to look for.
142 * \param pInfo Pointer to a KDB_MODULE_INFO struct which is filled on
143 * success.
144 *
145 * \retval TRUE Success - module found.
146 * \retval FALSE Failure - module not found.
147 *
148 * \sa KdbpSymFindModuleByName
149 * \sa KdbpSymFindModuleByIndex
150 */
151 BOOLEAN
152 KdbpSymFindModuleByAddress(IN PVOID Address,
153 OUT PKDB_MODULE_INFO pInfo)
154 {
155 return KdbpSymFindModule(Address, NULL, -1, pInfo);
156 }
157
158 /*! \brief Find module by name...
159 *
160 * \param Name Name of the module to look for.
161 * \param pInfo Pointer to a KDB_MODULE_INFO struct which is filled on
162 * success.
163 *
164 * \retval TRUE Success - module found.
165 * \retval FALSE Failure - module not found.
166 *
167 * \sa KdbpSymFindModuleByAddress
168 * \sa KdbpSymFindModuleByIndex
169 */
170 BOOLEAN
171 KdbpSymFindModuleByName(IN LPCWSTR Name,
172 OUT PKDB_MODULE_INFO pInfo)
173 {
174 return KdbpSymFindModule(NULL, Name, -1, pInfo);
175 }
176
177 /*! \brief Find module by index...
178 *
179 * \param Index Index of the module to return.
180 * \param pInfo Pointer to a KDB_MODULE_INFO struct which is filled on
181 * success.
182 *
183 * \retval TRUE Success - module found.
184 * \retval FALSE Failure - module not found.
185 *
186 * \sa KdbpSymFindModuleByName
187 * \sa KdbpSymFindModuleByAddress
188 */
189 BOOLEAN
190 KdbpSymFindModuleByIndex(IN INT Index,
191 OUT PKDB_MODULE_INFO pInfo)
192 {
193 return KdbpSymFindModule(NULL, NULL, Index, pInfo);
194 }
195
196 /*! \brief Print address...
197 *
198 * Tries to lookup line number, file name and function name for the given
199 * address and prints it.
200 * If no such information is found the address is printed in the format
201 * <module: offset>, otherwise the format will be
202 * <module: offset (filename:linenumber (functionname))>
203 *
204 * \retval TRUE Module containing \a Address was found, \a Address was printed.
205 * \retval FALSE No module containing \a Address was found, nothing was printed.
206 */
207 BOOLEAN
208 KdbSymPrintAddress(IN PVOID Address)
209 {
210 KDB_MODULE_INFO Info;
211 ULONG_PTR RelativeAddress;
212 NTSTATUS Status;
213 ULONG LineNumber;
214 CHAR FileName[256];
215 CHAR FunctionName[256];
216
217 if (!KdbpSymFindModuleByAddress(Address, &Info))
218 return FALSE;
219
220 RelativeAddress = (ULONG_PTR) Address - Info.Base;
221 Status = KdbSymGetAddressInformation(Info.RosSymInfo,
222 RelativeAddress,
223 &LineNumber,
224 FileName,
225 FunctionName);
226 if (NT_SUCCESS(Status))
227 {
228 DbgPrint("<%ws:%x (%s:%d (%s))>",
229 Info.Name, RelativeAddress, FileName, LineNumber, FunctionName);
230 }
231 else
232 {
233 DbgPrint("<%ws:%x>", Info.Name, RelativeAddress);
234 }
235
236 return TRUE;
237 }
238
239
240 /*! \brief Get information for an address (source file, line number,
241 * function name)
242 *
243 * \param SymbolInfo Pointer to ROSSYM_INFO.
244 * \param RelativeAddress Relative address to look up.
245 * \param LineNumber Pointer to an ULONG which is filled with the line
246 * number (can be NULL)
247 * \param FileName Pointer to an array of CHARs which gets filled with
248 * the filename (can be NULL)
249 * \param FunctionName Pointer to an array of CHARs which gets filled with
250 * the function name (can be NULL)
251 *
252 * \returns NTSTATUS error code.
253 * \retval STATUS_SUCCESS At least one of the requested informations was found.
254 * \retval STATUS_UNSUCCESSFUL None of the requested information was found.
255 */
256 NTSTATUS
257 KdbSymGetAddressInformation(IN PROSSYM_INFO RosSymInfo,
258 IN ULONG_PTR RelativeAddress,
259 OUT PULONG LineNumber OPTIONAL,
260 OUT PCH FileName OPTIONAL,
261 OUT PCH FunctionName OPTIONAL)
262 {
263 if (NULL == RosSymInfo)
264 {
265 return STATUS_UNSUCCESSFUL;
266 }
267
268 if (! RosSymGetAddressInformation(RosSymInfo, RelativeAddress, LineNumber,
269 FileName, FunctionName))
270 {
271 return STATUS_UNSUCCESSFUL;
272 }
273
274 return STATUS_SUCCESS;
275 }
276
277 /*! \brief Find cached symbol file.
278 *
279 * Looks through the list of cached symbol files and tries to find an already
280 * loaded one.
281 *
282 * \param FileName FileName of the symbol file to look for.
283 *
284 * \returns A pointer to the cached symbol info.
285 * \retval NULL No cached info found.
286 *
287 * \sa KdbpSymAddCachedFile
288 */
289 STATIC PROSSYM_INFO
290 KdbpSymFindCachedFile(IN PUNICODE_STRING FileName)
291 {
292 PIMAGE_SYMBOL_INFO_CACHE Current;
293 PLIST_ENTRY CurrentEntry;
294 KIRQL Irql;
295
296 DPRINT("Looking for cached symbol file %wZ\n", FileName);
297
298 KeAcquireSpinLock(&SymbolFileListLock, &Irql);
299
300 CurrentEntry = SymbolFileListHead.Flink;
301 while (CurrentEntry != (&SymbolFileListHead))
302 {
303 Current = CONTAINING_RECORD(CurrentEntry, IMAGE_SYMBOL_INFO_CACHE, ListEntry);
304
305 DPRINT("Current->FileName %wZ FileName %wZ\n", &Current->FileName, FileName);
306 if (RtlEqualUnicodeString(&Current->FileName, FileName, TRUE))
307 {
308 Current->RefCount++;
309 KeReleaseSpinLock(&SymbolFileListLock, Irql);
310 DPRINT("Found cached file!\n");
311 return Current->RosSymInfo;
312 }
313
314 CurrentEntry = CurrentEntry->Flink;
315 }
316
317 KeReleaseSpinLock(&SymbolFileListLock, Irql);
318
319 DPRINT("Cached file not found!\n");
320 return NULL;
321 }
322
323 /*! \brief Add a symbol file to the cache.
324 *
325 * \param FileName Filename of the symbol file.
326 * \param RosSymInfo Pointer to the symbol info.
327 *
328 * \sa KdbpSymRemoveCachedFile
329 */
330 STATIC VOID
331 KdbpSymAddCachedFile(IN PUNICODE_STRING FileName,
332 IN PROSSYM_INFO RosSymInfo)
333 {
334 PIMAGE_SYMBOL_INFO_CACHE CacheEntry;
335
336 DPRINT("Adding symbol file: RosSymInfo = %p\n", RosSymInfo);
337
338 /* allocate entry */
339 CacheEntry = ExAllocatePoolWithTag(NonPagedPool, sizeof (IMAGE_SYMBOL_INFO_CACHE), TAG_KDBS);
340 ASSERT(CacheEntry);
341 RtlZeroMemory(CacheEntry, sizeof (IMAGE_SYMBOL_INFO_CACHE));
342
343 /* fill entry */
344 RtlCreateUnicodeString(&CacheEntry->FileName, FileName->Buffer);
345 ASSERT(CacheEntry->FileName.Buffer);
346 CacheEntry->RefCount = 1;
347 CacheEntry->RosSymInfo = RosSymInfo;
348 InsertTailList(&SymbolFileListHead, &CacheEntry->ListEntry); /* FIXME: Lock list? */
349 }
350
351 /*! \brief Remove a symbol file (reference) from the cache.
352 *
353 * Tries to find a cache entry matching the given symbol info and decreases
354 * it's reference count. If the refcount is 0 after decreasing it the cache
355 * entry will be removed from the list and freed.
356 *
357 * \param RosSymInfo Pointer to the symbol info.
358 *
359 * \sa KdbpSymAddCachedFile
360 */
361 STATIC VOID
362 KdbpSymRemoveCachedFile(IN PROSSYM_INFO RosSymInfo)
363 {
364 PIMAGE_SYMBOL_INFO_CACHE Current;
365 PLIST_ENTRY CurrentEntry;
366 KIRQL Irql;
367
368 KeAcquireSpinLock(&SymbolFileListLock, &Irql);
369
370 CurrentEntry = SymbolFileListHead.Flink;
371 while (CurrentEntry != (&SymbolFileListHead))
372 {
373 Current = CONTAINING_RECORD(CurrentEntry, IMAGE_SYMBOL_INFO_CACHE, ListEntry);
374
375 if (Current->RosSymInfo == RosSymInfo) /* found */
376 {
377 ASSERT(Current->RefCount > 0);
378 Current->RefCount--;
379 if (Current->RefCount < 1)
380 {
381 RemoveEntryList(&Current->ListEntry);
382 RosSymDelete(Current->RosSymInfo);
383 ExFreePool(Current);
384 }
385 KeReleaseSpinLock(&SymbolFileListLock, Irql);
386 return;
387 }
388
389 CurrentEntry = CurrentEntry->Flink;
390 }
391
392 KeReleaseSpinLock(&SymbolFileListLock, Irql);
393 DPRINT1("Warning: Removing unknown symbol file: RosSymInfo = %p\n", RosSymInfo);
394 }
395
396 /*! \brief Loads a symbol file.
397 *
398 * \param FileName Filename of the symbol file to load.
399 * \param RosSymInfo Pointer to a ROSSYM_INFO which gets filled.
400 *
401 * \sa KdbpSymUnloadModuleSymbols
402 */
403 STATIC VOID
404 KdbpSymLoadModuleSymbols(IN PUNICODE_STRING FileName,
405 OUT PROSSYM_INFO *RosSymInfo)
406 {
407 OBJECT_ATTRIBUTES ObjectAttributes;
408 HANDLE FileHandle;
409 NTSTATUS Status;
410 IO_STATUS_BLOCK IoStatusBlock;
411
412 /* Allow KDB to break on module load */
413 KdbModuleLoaded(FileName);
414
415 if (! LoadSymbols)
416 {
417 *RosSymInfo = NULL;
418 return;
419 }
420
421 /* Try to find cached (already loaded) symbol file */
422 *RosSymInfo = KdbpSymFindCachedFile(FileName);
423 if (*RosSymInfo != NULL)
424 {
425 DPRINT("Found cached symbol file %wZ\n", FileName);
426 return;
427 }
428
429 /* Open the file */
430 InitializeObjectAttributes(&ObjectAttributes,
431 FileName,
432 0,
433 NULL,
434 NULL);
435
436 DPRINT("Attempting to open image: %wZ\n", FileName);
437
438 Status = ZwOpenFile(&FileHandle,
439 FILE_READ_ACCESS,
440 &ObjectAttributes,
441 &IoStatusBlock,
442 FILE_SHARE_READ|FILE_SHARE_WRITE,
443 FILE_SYNCHRONOUS_IO_NONALERT);
444 if (!NT_SUCCESS(Status))
445 {
446 DPRINT("Could not open image file: %wZ\n", &FileName);
447 return;
448 }
449
450 DPRINT("Loading symbols from %wZ...\n", FileName);
451
452 if (! RosSymCreateFromFile(&FileHandle, RosSymInfo))
453 {
454 DPRINT("Failed to load symbols from %wZ\n", FileName);
455 return;
456 }
457
458 ZwClose(FileHandle);
459
460 DPRINT("Symbols loaded.\n");
461
462 /* add file to cache */
463 KdbpSymAddCachedFile(FileName, *RosSymInfo);
464
465 DPRINT("Installed symbols: %wZ %p\n", FileName, *RosSymInfo);
466 }
467
468 /*! \brief Unloads symbol info.
469 *
470 * \param RosSymInfo Pointer to the symbol info to unload.
471 *
472 * \sa KdbpSymLoadModuleSymbols
473 */
474 STATIC VOID
475 KdbpSymUnloadModuleSymbols(IN PROSSYM_INFO RosSymInfo)
476 {
477 DPRINT("Unloading symbols\n");
478
479 if (RosSymInfo != NULL)
480 {
481 KdbpSymRemoveCachedFile(RosSymInfo);
482 }
483 }
484
485 /*! \brief Load symbol info for a user module.
486 *
487 * \param LdrModule Pointer to the module to load symbols for.
488 */
489 VOID
490 KdbSymLoadUserModuleSymbols(IN PLDR_DATA_TABLE_ENTRY LdrModule)
491 {
492 static WCHAR Prefix[] = L"\\??\\";
493 UNICODE_STRING KernelName;
494 DPRINT("LdrModule %p\n", LdrModule);
495
496 LdrModule->PatchInformation = NULL;
497
498 KernelName.MaximumLength = sizeof(Prefix) + LdrModule->FullDllName.Length;
499 KernelName.Length = KernelName.MaximumLength - sizeof(WCHAR);
500 KernelName.Buffer = ExAllocatePoolWithTag(PagedPool, KernelName.MaximumLength, TAG_KDBS);
501 if (NULL == KernelName.Buffer)
502 {
503 return;
504 }
505 memcpy(KernelName.Buffer, Prefix, sizeof(Prefix) - sizeof(WCHAR));
506 memcpy(KernelName.Buffer + sizeof(Prefix) / sizeof(WCHAR) - 1, LdrModule->FullDllName.Buffer,
507 LdrModule->FullDllName.Length);
508 KernelName.Buffer[KernelName.Length / sizeof(WCHAR)] = L'\0';
509
510 KdbpSymLoadModuleSymbols(&KernelName, (PROSSYM_INFO*)&LdrModule->PatchInformation);
511
512 ExFreePool(KernelName.Buffer);
513 }
514
515 /*! \brief Frees all symbols loaded for a process.
516 *
517 * \param Process Pointer to a process.
518 */
519 VOID
520 KdbSymFreeProcessSymbols(IN PEPROCESS Process)
521 {
522 PLIST_ENTRY CurrentEntry;
523 PLDR_DATA_TABLE_ENTRY Current;
524 PEPROCESS CurrentProcess;
525 PPEB Peb;
526
527 CurrentProcess = PsGetCurrentProcess();
528 if (CurrentProcess != Process)
529 {
530 KeAttachProcess(&Process->Pcb);
531 }
532 Peb = Process->Peb;
533 ASSERT(Peb);
534 ASSERT(Peb->Ldr);
535
536 CurrentEntry = Peb->Ldr->InLoadOrderModuleList.Flink;
537 while (CurrentEntry != &Peb->Ldr->InLoadOrderModuleList &&
538 CurrentEntry != NULL)
539 {
540 Current = CONTAINING_RECORD(CurrentEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
541
542 KdbpSymUnloadModuleSymbols(Current->PatchInformation);
543
544 CurrentEntry = CurrentEntry->Flink;
545 }
546 if (CurrentProcess != Process)
547 {
548 KeDetachProcess();
549 }
550 }
551
552 /*! \brief Load symbol info for a driver.
553 *
554 * \param Filename Filename of the driver.
555 * \param Module Pointer to the driver LDR_DATA_TABLE_ENTRY.
556 */
557 VOID
558 KdbSymLoadDriverSymbols(IN PUNICODE_STRING Filename,
559 IN PLDR_DATA_TABLE_ENTRY Module)
560 {
561 /* Load symbols for the image if available */
562 DPRINT("Loading driver %wZ symbols (driver @ %08x)\n", Filename, Module->DllBase);
563
564 Module->PatchInformation = NULL;
565
566 KdbpSymLoadModuleSymbols(Filename, (PROSSYM_INFO*)&Module->PatchInformation);
567 }
568
569 /*! \brief Unloads symbol info for a driver.
570 *
571 * \param ModuleObject Pointer to the driver LDR_DATA_TABLE_ENTRY.
572 */
573 VOID
574 KdbSymUnloadDriverSymbols(IN PLDR_DATA_TABLE_ENTRY ModuleObject)
575 {
576 /* Unload symbols for module if available */
577 KdbpSymUnloadModuleSymbols(ModuleObject->PatchInformation);
578 ModuleObject->PatchInformation = NULL;
579 }
580
581 /*! \brief Called when a symbol file is loaded by the loader?
582 *
583 * Tries to find a driver (.sys) or executable (.exe) with the same base name
584 * as the symbol file and sets the drivers/exes symbol info to the loaded
585 * module.
586 * Used to load ntoskrnl and hal symbols before the SystemRoot is available to us.
587 *
588 * \param FileName Filename for which the symbols are loaded.
589 */
590 VOID
591 KdbSymProcessBootSymbols(IN PCHAR FileName)
592 {
593 PLDR_DATA_TABLE_ENTRY ModuleObject;
594 UNICODE_STRING UnicodeString;
595 PLOADER_MODULE KeLoaderModules = (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
596 ANSI_STRING AnsiString;
597 ULONG i;
598 BOOLEAN IsRaw;
599
600 DPRINT("KdbSymProcessBootSymbols(%s)\n", FileName);
601
602 if (0 == _stricmp(FileName, "ntoskrnl.sym"))
603 {
604 RtlInitAnsiString(&AnsiString, "ntoskrnl.exe");
605 IsRaw = TRUE;
606 }
607 else
608 {
609 RtlInitAnsiString(&AnsiString, FileName);
610 IsRaw = FALSE;
611 }
612 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
613 ModuleObject = LdrGetModuleObject(&UnicodeString);
614 RtlFreeUnicodeString(&UnicodeString);
615
616 if (ModuleObject != NULL)
617 {
618 if (! LoadSymbols)
619 {
620 ModuleObject->PatchInformation = NULL;
621 return;
622 }
623
624 for (i = 0; i < KeLoaderBlock.ModsCount; i++)
625 {
626 if (0 == _stricmp(FileName, (PCHAR)KeLoaderModules[i].String))
627 {
628 break;
629 }
630 }
631 if (i < KeLoaderBlock.ModsCount)
632 {
633 KeLoaderModules[i].Reserved = 1;
634 if (ModuleObject->PatchInformation != NULL)
635 {
636 KdbpSymRemoveCachedFile(ModuleObject->PatchInformation);
637 }
638
639 if (IsRaw)
640 {
641 if (! RosSymCreateFromRaw((PVOID) KeLoaderModules[i].ModStart,
642 KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart,
643 (PROSSYM_INFO*)&ModuleObject->PatchInformation))
644 {
645 return;
646 }
647 }
648 else
649 {
650 if (! RosSymCreateFromMem((PVOID) KeLoaderModules[i].ModStart,
651 KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart,
652 (PROSSYM_INFO*)&ModuleObject->PatchInformation))
653 {
654 return;
655 }
656 }
657
658 /* add file to cache */
659 RtlInitAnsiString(&AnsiString, FileName);
660 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
661 KdbpSymAddCachedFile(&UnicodeString, ModuleObject->PatchInformation);
662 RtlFreeUnicodeString(&UnicodeString);
663
664 DPRINT("Installed symbols: %s@%08x-%08x %p\n",
665 FileName,
666 ModuleObject->DllBase,
667 ModuleObject->SizeOfImage + (ULONG)ModuleObject->DllBase,
668 ModuleObject->PatchInformation);
669 }
670 }
671 }
672
673 /*! \brief Initializes the KDB symbols implementation.
674 *
675 * \param NtoskrnlModuleObject LDR_DATA_TABLE_ENTRY of ntoskrnl.exe
676 * \param LdrHalModuleObject LDR_DATA_TABLE_ENTRY of hal.sys
677 */
678 VOID
679 KdbSymInit(IN PLDR_DATA_TABLE_ENTRY NtoskrnlModuleObject,
680 IN PLDR_DATA_TABLE_ENTRY LdrHalModuleObject)
681 {
682 PCHAR p1, p2;
683 int Found;
684 char YesNo;
685
686 NtoskrnlModuleObject->PatchInformation = NULL;
687 LdrHalModuleObject->PatchInformation = NULL;
688
689 InitializeListHead(&SymbolFileListHead);
690 KeInitializeSpinLock(&SymbolFileListLock);
691
692 #ifdef DBG
693 LoadSymbols = TRUE;
694 #else
695 LoadSymbols = FALSE;
696 #endif
697
698 /* Check the command line for /LOADSYMBOLS, /NOLOADSYMBOLS,
699 * /LOADSYMBOLS={YES|NO}, /NOLOADSYMBOLS={YES|NO} */
700 p1 = (PCHAR) KeLoaderBlock.CommandLine;
701 while('\0' != *p1 && NULL != (p2 = strchr(p1, '/')))
702 {
703 p2++;
704 Found = 0;
705 if (0 == _strnicmp(p2, "LOADSYMBOLS", 11))
706 {
707 Found = +1;
708 p2 += 11;
709 }
710 else if (0 == _strnicmp(p2, "NOLOADSYMBOLS", 13))
711 {
712 Found = -1;
713 p2 += 13;
714 }
715 if (0 != Found)
716 {
717 while (isspace(*p2))
718 {
719 p2++;
720 }
721 if ('=' == *p2)
722 {
723 p2++;
724 while (isspace(*p2))
725 {
726 p2++;
727 }
728 YesNo = toupper(*p2);
729 if ('N' == YesNo || 'F' == YesNo || '0' == YesNo)
730 {
731 Found = -1 * Found;
732 }
733 }
734 LoadSymbols = (0 < Found);
735 }
736 p1 = p2;
737 }
738
739 RosSymInitKernelMode();
740 }
741
742 /* EOF */