3 * Copyright (C) 1998-2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/dbg/kdb_symbols.c
22 * PURPOSE: Getting symbol information...
23 * PROGRAMMER: David Welch (welch@cwcom.net), ...
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
32 #include <internal/ntoskrnl.h>
33 #include <internal/ke.h>
34 #include <internal/i386/segment.h>
35 #include <internal/i386/mm.h>
36 #include <internal/module.h>
37 #include <internal/mm.h>
38 #include <internal/ps.h>
39 #include <internal/trap.h>
40 #include <ntdll/ldr.h>
41 #include <internal/safe.h>
42 #include <internal/kd.h>
43 #include <rosrtl/string.h>
46 #include <internal/debug.h>
49 #include "kdb_stabs.h"
51 /* GLOBALS ******************************************************************/
53 typedef struct _SYMBOLFILE_HEADER
{
58 } SYMBOLFILE_HEADER
, *PSYMBOLFILE_HEADER
;
60 typedef struct _IMAGE_SYMBOL_INFO_CACHE
{
63 UNICODE_STRING FileName
;
67 PVOID SymbolStringsBase
;
68 ULONG SymbolStringsLength
;
69 } IMAGE_SYMBOL_INFO_CACHE
, *PIMAGE_SYMBOL_INFO_CACHE
;
72 static LIST_ENTRY SymbolFileListHead
;
73 static KSPIN_LOCK SymbolFileListLock
;
76 /* FUNCTIONS ****************************************************************/
78 /*! \brief Find a user-mode module...
80 * \param Address If \a Address is not NULL the module containing \a Address
82 * \param Name If \a Name is not NULL the module named \a Name will be
84 * \param Index If \a Index is >= 0 the Index'th module will be returned.
85 * \param pInfo Pointer to a KDB_MODULE_INFO which is filled.
87 * \retval TRUE Module was found, \a pInfo was filled.
88 * \retval FALSE No module was found.
90 * \sa KdbpSymFindModule
93 KdbpSymFindUserModule(IN PVOID Address OPTIONAL
,
94 IN LPCWSTR Name OPTIONAL
,
95 IN INT Index OPTIONAL
,
96 OUT PKDB_MODULE_INFO pInfo
)
98 PLIST_ENTRY current_entry
;
100 PEPROCESS CurrentProcess
;
104 CurrentProcess
= PsGetCurrentProcess();
105 if (CurrentProcess
!= NULL
)
107 Peb
= CurrentProcess
->Peb
;
115 current_entry
= Peb
->Ldr
->InLoadOrderModuleList
.Flink
;
117 while (current_entry
!= &Peb
->Ldr
->InLoadOrderModuleList
&&
118 current_entry
!= NULL
)
120 current
= CONTAINING_RECORD(current_entry
, LDR_MODULE
, InLoadOrderModuleList
);
122 if ((Address
!= NULL
&& (Address
>= (PVOID
)current
->BaseAddress
&&
123 Address
< (PVOID
)((char *)current
->BaseAddress
+ current
->SizeOfImage
))) ||
124 (Name
!= NULL
&& _wcsicmp(current
->BaseDllName
.Buffer
, Name
) == 0) ||
125 (Index
>= 0 && Count
++ == Index
))
127 INT Length
= current
->BaseDllName
.Length
;
130 wcsncpy(pInfo
->Name
, current
->BaseDllName
.Buffer
, Length
);
131 pInfo
->Name
[Length
] = L
'\0';
132 pInfo
->Base
= (ULONG_PTR
)current
->BaseAddress
;
133 pInfo
->Size
= current
->SizeOfImage
;
134 pInfo
->SymbolInfo
= ¤t
->SymbolInfo
;
137 current_entry
= current_entry
->Flink
;
143 /*! \brief Find a kernel-mode module...
145 * Works like \a KdbpSymFindUserModule.
147 * \sa KdbpSymFindUserModule
150 KdbpSymFindModule(IN PVOID Address OPTIONAL
,
151 IN LPCWSTR Name OPTIONAL
,
152 IN INT Index OPTIONAL
,
153 OUT PKDB_MODULE_INFO pInfo
)
155 PLIST_ENTRY current_entry
;
156 MODULE_TEXT_SECTION
* current
;
157 extern LIST_ENTRY ModuleTextListHead
;
160 current_entry
= ModuleTextListHead
.Flink
;
162 while (current_entry
!= &ModuleTextListHead
&&
163 current_entry
!= NULL
)
165 current
= CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
, ListEntry
);
167 if ((Address
!= NULL
&& (Address
>= (PVOID
)current
->Base
&&
168 Address
< (PVOID
)(current
->Base
+ current
->Length
))) ||
169 (Name
!= NULL
&& _wcsicmp(current
->Name
, Name
) == 0) ||
170 (Index
>= 0 && Count
++ == Index
))
172 wcsncpy(pInfo
->Name
, current
->Name
, 255);
173 pInfo
->Name
[255] = L
'\0';
174 pInfo
->Base
= (ULONG_PTR
)current
->Base
;
175 pInfo
->Size
= current
->Length
;
176 pInfo
->SymbolInfo
= ¤t
->SymbolInfo
;
179 current_entry
= current_entry
->Flink
;
182 return KdbpSymFindUserModule(Address
, Name
, Index
-Count
, pInfo
);
185 /*! \brief Find module by address...
187 * \param Address Any address inside the module to look for.
188 * \param pInfo Pointer to a KDB_MODULE_INFO struct which is filled on
191 * \retval TRUE Success - module found.
192 * \retval FALSE Failure - module not found.
194 * \sa KdbpSymFindModuleByName
195 * \sa KdbpSymFindModuleByIndex
198 KdbpSymFindModuleByAddress(IN PVOID Address
,
199 OUT PKDB_MODULE_INFO pInfo
)
201 return KdbpSymFindModule(Address
, NULL
, -1, pInfo
);
204 /*! \brief Find module by name...
206 * \param Name Name of the module to look for.
207 * \param pInfo Pointer to a KDB_MODULE_INFO struct which is filled on
210 * \retval TRUE Success - module found.
211 * \retval FALSE Failure - module not found.
213 * \sa KdbpSymFindModuleByAddress
214 * \sa KdbpSymFindModuleByIndex
217 KdbpSymFindModuleByName(IN LPCWSTR Name
,
218 OUT PKDB_MODULE_INFO pInfo
)
220 return KdbpSymFindModule(NULL
, Name
, -1, pInfo
);
223 /*! \brief Find module by index...
225 * \param Index Index of the module to return.
226 * \param pInfo Pointer to a KDB_MODULE_INFO struct which is filled on
229 * \retval TRUE Success - module found.
230 * \retval FALSE Failure - module not found.
232 * \sa KdbpSymFindModuleByName
233 * \sa KdbpSymFindModuleByAddress
236 KdbpSymFindModuleByIndex(IN INT Index
,
237 OUT PKDB_MODULE_INFO pInfo
)
239 return KdbpSymFindModule(NULL
, NULL
, Index
, pInfo
);
242 /*! \brief Print address...
244 * Tries to lookup line number, file name and function name for the given
245 * address and prints it.
246 * If no such information is found the address is printed in the format
247 * <module: offset>, otherwise the format will be
248 * <module: offset (filename:linenumber (functionname))>
250 * \retval TRUE Module containing \a Address was found, \a Address was printed.
251 * \retval FALSE No module containing \a Address was found, nothing was printed.
254 KdbSymPrintAddress(IN PVOID Address
)
256 KDB_MODULE_INFO Info
;
257 ULONG_PTR RelativeAddress
;
261 CHAR FunctionName
[256];
263 if (!KdbpSymFindModuleByAddress(Address
, &Info
))
266 RelativeAddress
= (ULONG_PTR
) Address
- Info
.Base
;
267 Status
= KdbSymGetAddressInformation(Info
.SymbolInfo
,
272 if (NT_SUCCESS(Status
))
274 DbgPrint("<%ws: %x (%s:%d (%s))>",
275 Info
.Name
, RelativeAddress
, FileName
, LineNumber
, FunctionName
);
279 DbgPrint("<%ws: %x>", Info
.Name
, RelativeAddress
);
286 /*! \brief Get information for an address (source file, line number,
289 * \param SymbolInfo Pointer to IMAGE_SYMBOL_INFO.
290 * \param RelativeAddress Relative address to look up.
291 * \param LineNumber Pointer to an ULONG which is filled with the line
292 * number (can be NULL)
293 * \param FileName Pointer to an array of CHARs which gets filled with
294 * the filename (can be NULL)
295 * \param FunctionName Pointer to an array of CHARs which gets filled with
296 * the function name (can be NULL)
298 * \returns NTSTATUS error code.
299 * \retval STATUS_SUCCESS At least one of the requested informations was found.
300 * \retval STATUS_UNSUCCESSFUL None of the requested information was found.
303 KdbSymGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo
,
304 IN ULONG_PTR RelativeAddress
,
305 OUT PULONG LineNumber OPTIONAL
,
306 OUT PCH FileName OPTIONAL
,
307 OUT PCH FunctionName OPTIONAL
)
309 PSTAB_ENTRY FunctionEntry
= NULL
, FileEntry
= NULL
, LineEntry
= NULL
;
311 DPRINT("RelativeAddress = 0x%08x\n", RelativeAddress
);
313 if (SymbolInfo
->SymbolsBase
== NULL
|| SymbolInfo
->SymbolsLength
== 0 ||
314 SymbolInfo
->SymbolStringsBase
== NULL
|| SymbolInfo
->SymbolStringsLength
== 0)
316 return STATUS_UNSUCCESSFUL
;
319 #ifdef PEDANTIC_STABS
320 if (RelativeAddress
>= SymbolInfo
->ImageSize
)
322 DPRINT("Address is not within .text section. RelativeAddress %p Length 0x%x\n",
323 RelativeAddress
, SymbolInfo
->ImageSize
);
324 return STATUS_UNSUCCESSFUL
;
328 ASSERT(LineNumber
|| FileName
|| FunctionName
);
330 if (LineNumber
!= NULL
|| FunctionName
!= NULL
)
332 /* find stab entry for function */
333 FunctionEntry
= KdbpStabFindEntry(SymbolInfo
, N_FUN
, (PVOID
)RelativeAddress
, NULL
);
334 if (FunctionEntry
== NULL
)
336 DPRINT("No function stab entry found. RelativeAddress %p\n", RelativeAddress
);
339 if (LineNumber
!= NULL
&& FunctionEntry
!= NULL
)
341 /* find stab entry for line number */
342 ULONG_PTR FunctionRelativeAddress
= FunctionEntry
->n_value
- (ULONG_PTR
)SymbolInfo
->ImageBase
;
343 ULONG_PTR AddrFound
= 0;
344 PSTAB_ENTRY NextLineEntry
;
346 LineEntry
= NextLineEntry
= FunctionEntry
;
347 while (NextLineEntry
!= NULL
)
350 if ((ULONG_PTR
)NextLineEntry
>= ((ULONG_PTR
)SymbolInfo
->SymbolsBase
+ SymbolInfo
->SymbolsLength
))
352 if (NextLineEntry
->n_type
== N_FUN
)
354 if (NextLineEntry
->n_type
!= N_SLINE
)
357 if (((NextLineEntry
->n_value
+FunctionRelativeAddress
) <= RelativeAddress
) &&
358 (NextLineEntry
->n_value
> AddrFound
))
360 AddrFound
= NextLineEntry
->n_value
;
361 LineEntry
= NextLineEntry
;
367 if (FileName
!= NULL
)
369 /* find stab entry for file name */
373 FileEntry
= KdbpStabFindEntry(SymbolInfo
, N_SO
, (PVOID
)RelativeAddress
, NULL
);
374 if (FileEntry
!= NULL
)
376 p
= (PCHAR
)SymbolInfo
->SymbolStringsBase
+ FileEntry
->n_strx
;
378 if (p
[Length
- 1] == '/' || p
[Length
- 1] == '\\') /* source dir */
379 FileEntry
= KdbpStabFindEntry(SymbolInfo
, N_SO
, (PVOID
)RelativeAddress
, FileEntry
+ 1);
381 if (FileEntry
== NULL
)
383 DPRINT("No filename stab entry found. RelativeAddress %p\n", RelativeAddress
);
387 if (((LineNumber
!= NULL
&& LineEntry
== NULL
) || LineNumber
== NULL
) &&
388 ((FileName
!= NULL
&& FileEntry
== NULL
) || FileName
== NULL
) &&
389 ((FunctionName
!= NULL
&& FunctionEntry
== NULL
) || FunctionName
== NULL
))
391 DPRINT("None of the requested information was found!\n");
392 return STATUS_UNSUCCESSFUL
;
395 if (LineNumber
!= NULL
)
398 if (LineEntry
!= NULL
)
399 *LineNumber
= LineEntry
->n_desc
;
401 if (FileName
!= NULL
)
404 if (FileEntry
!= NULL
)
406 Name
= (PCHAR
)SymbolInfo
->SymbolStringsBase
+ FileEntry
->n_strx
;
408 strcpy(FileName
, Name
);
410 if (FunctionName
!= NULL
)
413 if (FunctionEntry
!= NULL
)
414 Name
= (PCHAR
)SymbolInfo
->SymbolStringsBase
+ FunctionEntry
->n_strx
;
415 strcpy(FunctionName
, Name
);
416 if ((p
= strchr(FunctionName
, ':')) != NULL
) /* remove extra info from function name */
420 return STATUS_SUCCESS
;
424 /*! \brief Get absolute source-line number or function address
426 * \param SymbolInfo IMAGE_SYMBOL_INFO of the module containing source file/line number.
427 * \param FileName Source filename.
428 * \param LineNumber Line number in source file.
429 * \param FuncName Function name.
430 * \param Address Filled with the address on success.
432 * \retval TRUE Success.
433 * \retval FALSE Failure.
436 KdbpSymGetSourceAddress(IN PIMAGE_SYMBOL_INFO SymbolInfo
,
438 IN ULONG LineNumber OPTIONAL
,
439 IN PCHAR FuncName OPTIONAL
,
442 PSTAB_ENTRY Entry
, FunctionEntry
= NULL
;
444 CHAR Buffer
[512] = "";
445 INT Length
, FileNameLength
, FuncNameLength
= 0;
447 if (FuncName
== NULL
&& LineNumber
< 1)
450 FileNameLength
= strlen(FileName
);
451 FuncNameLength
= strlen(FuncName
);
452 for (Entry
= SymbolInfo
->SymbolsBase
;
453 (ULONG_PTR
)Entry
< (ULONG_PTR
)(SymbolInfo
->SymbolsBase
+ SymbolInfo
->SymbolsLength
);
456 if (Entry
->n_type
!= N_SO
)
459 SymbolName
= (PCHAR
)SymbolInfo
->SymbolStringsBase
+ Entry
->n_strx
;
460 Length
= strlen(SymbolName
);
461 if (SymbolName
[Length
- 1] == '/' ||
462 SymbolName
[Length
- 1] == '\\')
464 strncpy(Buffer
, SymbolName
, sizeof (Buffer
) - 1);
465 Buffer
[sizeof (Buffer
) - 1] = '\0';
468 strncat(Buffer
, SymbolName
, sizeof (Buffer
) - 1);
469 Buffer
[sizeof (Buffer
) - 1] = '\0';
471 Length
= strlen(Buffer
);
472 if (strcmp(Buffer
+ Length
- FileNameLength
, FileName
) != 0)
476 for (;(ULONG_PTR
)Entry
< (ULONG_PTR
)(SymbolInfo
->SymbolsBase
+ SymbolInfo
->SymbolsLength
);
479 if (Entry
->n_type
== N_FUN
)
480 FunctionEntry
= Entry
;
481 else if (Entry
->n_type
== N_SO
)
483 else if (Entry
->n_type
!= N_SLINE
|| LineNumber
< 1)
486 if (LineNumber
> 0 && Entry
->n_desc
!= LineNumber
)
488 else /* if (FunctionName != NULL) */
490 SymbolName
= (PCHAR
)SymbolInfo
->SymbolStringsBase
+ Entry
->n_strx
;
491 p
= strchr(SymbolName
, ':');
494 Length
= p
- SymbolName
;
495 if (Length
!= FuncNameLength
)
497 if (strncmp(FuncName
, SymbolName
, Length
) != 0)
502 if (Entry
->n_type
== N_FUN
)
504 *Address
= (PVOID
)Entry
->n_value
; /* FIXME: relocate address */
508 if (FunctionEntry
== NULL
)
511 *Address
= (PVOID
)((ULONG_PTR
)Entry
->n_value
+ FunctionEntry
->n_value
); /* FIXME: relocate address */
520 /*! \brief Find cached symbol file.
522 * Looks through the list of cached symbol files and tries to find an already
525 * \param FileName FileName of the symbol file to look for.
527 * \returns A pointer to the cached symbol info.
528 * \retval NULL No cached info found.
530 * \sa KdbpSymAddCachedFile
532 STATIC PIMAGE_SYMBOL_INFO_CACHE
533 KdbpSymFindCachedFile(IN PUNICODE_STRING FileName
)
535 PIMAGE_SYMBOL_INFO_CACHE Current
;
536 PLIST_ENTRY CurrentEntry
;
539 DPRINT("Looking for cached symbol file %wZ\n", FileName
);
541 KeAcquireSpinLock(&SymbolFileListLock
, &Irql
);
543 CurrentEntry
= SymbolFileListHead
.Flink
;
544 while (CurrentEntry
!= (&SymbolFileListHead
))
546 Current
= CONTAINING_RECORD(CurrentEntry
, IMAGE_SYMBOL_INFO_CACHE
, ListEntry
);
548 DPRINT("Current->FileName %wZ FileName %wZ\n", &Current
->FileName
, FileName
);
549 if (RtlEqualUnicodeString(&Current
->FileName
, FileName
, TRUE
))
551 KeReleaseSpinLock(&SymbolFileListLock
, Irql
);
552 DPRINT("Found cached file!\n");
556 CurrentEntry
= CurrentEntry
->Flink
;
559 KeReleaseSpinLock(&SymbolFileListLock
, Irql
);
561 DPRINT("Cached file not found!\n");
565 /*! \brief Add a symbol file to the cache.
567 * \param FileName Filename of the symbol file.
568 * \param SymbolInfo Pointer to the symbol info.
570 * \sa KdbpSymRemoveCachedFile
573 KdbpSymAddCachedFile(IN PUNICODE_STRING FileName
,
574 IN PIMAGE_SYMBOL_INFO SymbolInfo
)
576 PIMAGE_SYMBOL_INFO_CACHE CacheEntry
;
578 DPRINT("Adding symbol file: FileBuffer = %p, ImageBase = %p\n",
579 SymbolInfo
->FileBuffer
, SymbolInfo
->ImageBase
);
582 CacheEntry
= ExAllocatePool(NonPagedPool
, sizeof (IMAGE_SYMBOL_INFO_CACHE
));
584 RtlZeroMemory(CacheEntry
, sizeof (IMAGE_SYMBOL_INFO_CACHE
));
587 RtlCreateUnicodeString(&CacheEntry
->FileName
, FileName
->Buffer
);
588 ASSERT(CacheEntry
->FileName
.Buffer
);
589 CacheEntry
->RefCount
= 1;
590 CacheEntry
->FileBuffer
= SymbolInfo
->FileBuffer
;
591 CacheEntry
->SymbolsBase
= SymbolInfo
->SymbolsBase
;
592 CacheEntry
->SymbolsLength
= SymbolInfo
->SymbolsLength
;
593 CacheEntry
->SymbolStringsBase
= SymbolInfo
->SymbolStringsBase
;
594 CacheEntry
->SymbolStringsLength
= SymbolInfo
->SymbolStringsLength
;
595 InsertTailList(&SymbolFileListHead
, &CacheEntry
->ListEntry
); /* FIXME: Lock list? */
598 /*! \brief Remove a symbol file (reference) from the cache.
600 * Tries to find a cache entry matching the given symbol info and decreases
601 * it's reference count. If the refcount is 0 after decreasing it the cache
602 * entry will be removed from the list and freed.
604 * \param SymbolInfo Pointer to the symbol info.
606 * \sa KdbpSymAddCachedFile
609 KdbpSymRemoveCachedFile(IN PIMAGE_SYMBOL_INFO SymbolInfo
)
611 PIMAGE_SYMBOL_INFO_CACHE Current
;
612 PLIST_ENTRY CurrentEntry
;
615 KeAcquireSpinLock(&SymbolFileListLock
, &Irql
);
617 CurrentEntry
= SymbolFileListHead
.Flink
;
618 while (CurrentEntry
!= (&SymbolFileListHead
))
620 Current
= CONTAINING_RECORD(CurrentEntry
, IMAGE_SYMBOL_INFO_CACHE
, ListEntry
);
622 if (Current
->FileBuffer
== SymbolInfo
->FileBuffer
) /* found */
624 ASSERT(Current
->RefCount
> 0);
626 if (Current
->RefCount
< 1)
628 RemoveEntryList(&Current
->ListEntry
);
629 ExFreePool(Current
->FileBuffer
);
632 KeReleaseSpinLock(&SymbolFileListLock
, Irql
);
636 CurrentEntry
= CurrentEntry
->Flink
;
639 KeReleaseSpinLock(&SymbolFileListLock
, Irql
);
640 DPRINT1("Warning: Removing unknown symbol file: FileBuffer = %p, ImageBase = %p\n",
641 SymbolInfo
->FileBuffer
, SymbolInfo
->ImageBase
);
644 /*! \brief Loads a symbol file.
646 * \param FileName Filename of the symbol file to load.
647 * \param SymbolInfo Pointer to a SymbolInfo which gets filled.
649 * \sa KdbpSymUnloadModuleSymbols
652 KdbpSymLoadModuleSymbols(IN PUNICODE_STRING FileName
,
653 OUT PIMAGE_SYMBOL_INFO SymbolInfo
)
655 FILE_STANDARD_INFORMATION FileStdInfo
;
656 OBJECT_ATTRIBUTES ObjectAttributes
;
657 WCHAR TmpFileName
[MAX_PATH
];
658 UNICODE_STRING SymFileName
;
664 IO_STATUS_BLOCK IoStatusBlock
;
665 PSYMBOLFILE_HEADER SymbolFileHeader
;
666 PIMAGE_SYMBOL_INFO_CACHE CachedSymbolFile
;
668 /* Get the path to the symbol store */
669 wcscpy(TmpFileName
, L
"\\SystemRoot\\symbols\\");
671 /* Get the symbol filename from the module name */
672 Start
= wcsrchr(FileName
->Buffer
, L
'\\');
674 Start
= FileName
->Buffer
;
678 Ext
= wcsrchr(FileName
->Buffer
, L
'.');
680 Length
= Ext
- Start
;
682 Length
= wcslen(Start
);
684 wcsncat(TmpFileName
, Start
, Length
);
685 wcscat(TmpFileName
, L
".sym");
686 RtlInitUnicodeString(&SymFileName
, TmpFileName
);
688 /* Try to find cached (already loaded) symbol file */
689 CachedSymbolFile
= KdbpSymFindCachedFile(&SymFileName
);
690 if (CachedSymbolFile
!= NULL
)
692 DPRINT("Found cached symbol file %wZ\n", &SymFileName
);
693 CachedSymbolFile
->RefCount
++;
694 SymbolInfo
->FileBuffer
= CachedSymbolFile
->FileBuffer
;
695 SymbolInfo
->SymbolsBase
= CachedSymbolFile
->SymbolsBase
;
696 SymbolInfo
->SymbolsLength
= CachedSymbolFile
->SymbolsLength
;
697 SymbolInfo
->SymbolStringsBase
= CachedSymbolFile
->SymbolStringsBase
;
698 SymbolInfo
->SymbolStringsLength
= CachedSymbolFile
->SymbolStringsLength
;
703 InitializeObjectAttributes(&ObjectAttributes
,
709 DPRINT("Attempting to open symbols: %wZ\n", &SymFileName
);
711 Status
= ZwOpenFile(&FileHandle
,
716 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_NO_INTERMEDIATE_BUFFERING
);
717 if (!NT_SUCCESS(Status
))
719 DPRINT("Could not open symbol file: %wZ\n", &SymFileName
);
723 DPRINT("Loading symbols from %wZ...\n", &SymFileName
);
725 /* Get the size of the file */
726 Status
= ZwQueryInformationFile(FileHandle
,
730 FileStandardInformation
);
731 if (!NT_SUCCESS(Status
))
733 DPRINT("Could not get file size\n");
738 DPRINT("Symbol file is %08x bytes\n", FileStdInfo
.EndOfFile
.u
.LowPart
);
740 /* Allocate nonpageable memory for symbol file */
741 FileBuffer
= ExAllocatePool(NonPagedPool
,
742 FileStdInfo
.AllocationSize
.u
.LowPart
);
744 if (FileBuffer
== NULL
)
746 DPRINT("Could not allocate memory for symbol file\n");
751 /* Load file into memory chunk */
752 Status
= ZwReadFile(FileHandle
,
756 FileStdInfo
.EndOfFile
.u
.LowPart
,
758 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
760 DPRINT("Could not read symbol file into memory (Status 0x%x)\n", Status
);
761 ExFreePool(FileBuffer
);
768 DPRINT("Symbols loaded.\n");
770 SymbolFileHeader
= (PSYMBOLFILE_HEADER
) FileBuffer
;
771 SymbolInfo
->FileBuffer
= FileBuffer
;
772 SymbolInfo
->SymbolsBase
= FileBuffer
+ SymbolFileHeader
->StabsOffset
;
773 SymbolInfo
->SymbolsLength
= SymbolFileHeader
->StabsLength
;
774 SymbolInfo
->SymbolStringsBase
= FileBuffer
+ SymbolFileHeader
->StabstrOffset
;
775 SymbolInfo
->SymbolStringsLength
= SymbolFileHeader
->StabstrLength
;
777 /* add file to cache */
778 KdbpSymAddCachedFile(&SymFileName
, SymbolInfo
);
780 DPRINT("Installed stabs: %wZ (%08x-%08x,%08x)\n",
782 SymbolInfo
->SymbolsBase
,
783 SymbolInfo
->SymbolsLength
+ SymbolInfo
->SymbolsBase
,
784 SymbolInfo
->SymbolStringsBase
);
787 /*! \brief Unloads symbol info.
789 * \param SymbolInfo Pointer to the symbol info to unload.
791 * \sa KdbpSymLoadModuleSymbols
794 KdbpSymUnloadModuleSymbols(IN PIMAGE_SYMBOL_INFO SymbolInfo
)
796 DPRINT("Unloading symbols\n");
798 if (SymbolInfo
!= NULL
&& SymbolInfo
->FileBuffer
!= NULL
&&
799 (PVOID
)SymbolInfo
->ImageBase
!= NULL
)
801 KdbpSymRemoveCachedFile(SymbolInfo
);
802 SymbolInfo
->FileBuffer
= NULL
;
803 SymbolInfo
->SymbolsBase
= NULL
;
804 SymbolInfo
->SymbolsLength
= 0;
808 /*! \brief Load symbol info for a user module.
810 * \param LdrModule Pointer to the module to load symbols for.
813 KdbSymLoadUserModuleSymbols(IN PLDR_MODULE LdrModule
)
815 DPRINT("LdrModule %p\n", LdrModule
);
817 RtlZeroMemory(&LdrModule
->SymbolInfo
, sizeof (LdrModule
->SymbolInfo
));
818 LdrModule
->SymbolInfo
.ImageBase
= (ULONG_PTR
)LdrModule
->BaseAddress
;
819 LdrModule
->SymbolInfo
.ImageSize
= LdrModule
->SizeOfImage
;
821 KdbpSymLoadModuleSymbols(&LdrModule
->FullDllName
, &LdrModule
->SymbolInfo
);
824 /*! \brief Frees all symbols loaded for a process.
826 * \param Process Pointer to a process.
829 KdbSymFreeProcessSymbols(IN PEPROCESS Process
)
831 PLIST_ENTRY CurrentEntry
;
833 PIMAGE_SYMBOL_INFO SymbolInfo
;
834 PEPROCESS CurrentProcess
;
837 CurrentProcess
= PsGetCurrentProcess();
838 if (CurrentProcess
!= Process
)
840 KeAttachProcess(&Process
->Pcb
);
846 CurrentEntry
= Peb
->Ldr
->InLoadOrderModuleList
.Flink
;
847 while (CurrentEntry
!= &Peb
->Ldr
->InLoadOrderModuleList
&&
848 CurrentEntry
!= NULL
)
850 Current
= CONTAINING_RECORD(CurrentEntry
, LDR_MODULE
, InLoadOrderModuleList
);
852 SymbolInfo
= &Current
->SymbolInfo
;
853 KdbpSymUnloadModuleSymbols(SymbolInfo
);
855 CurrentEntry
= CurrentEntry
->Flink
;
857 if (CurrentProcess
!= Process
)
863 /*! \brief Load symbol info for a driver.
865 * \param Filename Filename of the driver.
866 * \param Module Pointer to the driver MODULE_OBJECT.
869 KdbSymLoadDriverSymbols(IN PUNICODE_STRING Filename
,
870 IN PMODULE_OBJECT Module
)
872 /* Load symbols for the image if available */
873 DPRINT("Loading driver %wZ symbols (driver @ %08x)\n", Filename
, Module
->Base
);
875 RtlZeroMemory(&Module
->TextSection
->SymbolInfo
, sizeof (Module
->TextSection
->SymbolInfo
));
876 Module
->TextSection
->SymbolInfo
.ImageBase
= Module
->TextSection
->Base
;
877 Module
->TextSection
->SymbolInfo
.ImageSize
= Module
->TextSection
->Length
;
879 KdbpSymLoadModuleSymbols(Filename
, &Module
->TextSection
->SymbolInfo
);
882 /*! \brief Unloads symbol info for a driver.
884 * \param ModuleObject Pointer to the driver MODULE_OBJECT.
887 KdbSymUnloadDriverSymbols(IN PMODULE_OBJECT ModuleObject
)
889 /* Unload symbols for module if available */
890 KdbpSymUnloadModuleSymbols(&ModuleObject
->TextSection
->SymbolInfo
);
893 /*! \brief Called when a symbol file is loaded by the loader?
895 * Tries to find a driver (.sys) or executable (.exe) with the same base name
896 * as the symbol file and sets the drivers/exes symbol info to the loaded
898 * Used to load ntoskrnl and hal symbols before the SystemRoot is available to us.
900 * \param ModuleLoadBase Base address of the loaded symbol file.
901 * \param FileName Filename of the symbol file.
902 * \param Length Length of the loaded symbol file/module.
905 KdbSymProcessSymbolFile(IN PVOID ModuleLoadBase
,
909 PMODULE_OBJECT ModuleObject
;
910 UNICODE_STRING ModuleName
;
911 CHAR TmpBaseName
[MAX_PATH
];
912 CHAR TmpFileName
[MAX_PATH
];
913 PSYMBOLFILE_HEADER SymbolFileHeader
;
914 PIMAGE_SYMBOL_INFO SymbolInfo
;
915 ANSI_STRING AnsiString
;
918 DPRINT("Module %s is a symbol file\n", FileName
);
920 strncpy(TmpBaseName
, FileName
, MAX_PATH
-1);
921 TmpBaseName
[MAX_PATH
-1] = '\0';
922 /* remove the extension '.sym' */
923 Extension
= strrchr(TmpBaseName
, '.');
924 if (Extension
&& 0 == _stricmp(Extension
, ".sym"))
929 DPRINT("base: %s (Length %d)\n", TmpBaseName
, Length
);
931 strcpy(TmpFileName
, TmpBaseName
);
932 strcat(TmpFileName
, ".sys");
933 RtlInitAnsiString(&AnsiString
, TmpFileName
);
935 RtlAnsiStringToUnicodeString(&ModuleName
, &AnsiString
, TRUE
);
936 ModuleObject
= LdrGetModuleObject(&ModuleName
);
937 RtlFreeUnicodeString(&ModuleName
);
938 if (ModuleObject
== NULL
)
940 strcpy(TmpFileName
, TmpBaseName
);
941 strcat(TmpFileName
, ".exe");
942 RtlInitAnsiString(&AnsiString
, TmpFileName
);
943 RtlAnsiStringToUnicodeString(&ModuleName
, &AnsiString
, TRUE
);
944 ModuleObject
= LdrGetModuleObject(&ModuleName
);
945 RtlFreeUnicodeString(&ModuleName
);
947 if (ModuleObject
!= NULL
)
949 SymbolInfo
= (PIMAGE_SYMBOL_INFO
) &ModuleObject
->TextSection
->SymbolInfo
;
950 if (SymbolInfo
->FileBuffer
!= NULL
)
952 KdbpSymRemoveCachedFile(SymbolInfo
);
955 SymbolFileHeader
= (PSYMBOLFILE_HEADER
) ModuleLoadBase
;
956 SymbolInfo
->FileBuffer
= ModuleLoadBase
;
957 SymbolInfo
->SymbolsBase
= ModuleLoadBase
+ SymbolFileHeader
->StabsOffset
;
958 SymbolInfo
->SymbolsLength
= SymbolFileHeader
->StabsLength
;
959 SymbolInfo
->SymbolStringsBase
= ModuleLoadBase
+ SymbolFileHeader
->StabstrOffset
;
960 SymbolInfo
->SymbolStringsLength
= SymbolFileHeader
->StabstrLength
;
961 DPRINT("Installed stabs: %s@%08x-%08x (%08x-%08x,%08x)\n",
963 ModuleObject
->Base
, ModuleObject
->Length
+ ModuleObject
->Base
,
964 SymbolInfo
->SymbolsBase
,
965 SymbolInfo
->SymbolsLength
+ SymbolInfo
->SymbolsBase
,
966 SymbolInfo
->SymbolStringsBase
);
970 /*! \brief Initializes the KDB symbols implementation.
972 * \param NtoskrnlTextSection MODULE_TEXT_SECTION of ntoskrnl.exe
973 * \param LdrHalTextSection MODULE_TEXT_SECTION of hal.sys
976 KdbSymInit(IN PMODULE_TEXT_SECTION NtoskrnlTextSection
,
977 IN PMODULE_TEXT_SECTION LdrHalTextSection
)
979 RtlZeroMemory(&NtoskrnlTextSection
->SymbolInfo
, sizeof(NtoskrnlTextSection
->SymbolInfo
));
980 NtoskrnlTextSection
->SymbolInfo
.ImageBase
= NtoskrnlTextSection
->OptionalHeader
->ImageBase
;
981 NtoskrnlTextSection
->SymbolInfo
.ImageSize
= NtoskrnlTextSection
->Length
;
983 RtlZeroMemory(&LdrHalTextSection
->SymbolInfo
, sizeof(LdrHalTextSection
->SymbolInfo
));
984 LdrHalTextSection
->SymbolInfo
.ImageBase
= LdrHalTextSection
->OptionalHeader
->ImageBase
;
985 LdrHalTextSection
->SymbolInfo
.ImageSize
= LdrHalTextSection
->Length
;
987 InitializeListHead(&SymbolFileListHead
);
988 KeInitializeSpinLock(&SymbolFileListLock
);