--- /dev/null
+/*
+ * ReactOS kernel
+ * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * PROJECT: ReactOS kernel
+ * FILE: ntoskrnl/ke/i386/exp.c
+ * PURPOSE: Handling exceptions
+ * PROGRAMMER: David Welch (welch@cwcom.net)
+ * REVISION HISTORY:
+ * ??/??/??: Created
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <ddk/ntddk.h>
+#include <roscfg.h>
+#include <internal/ntoskrnl.h>
+#include <internal/ke.h>
+#include <internal/i386/segment.h>
+#include <internal/i386/mm.h>
+#include <internal/module.h>
+#include <internal/mm.h>
+#include <internal/ps.h>
+#include <internal/trap.h>
+#include <ntdll/ldr.h>
+#include <internal/safe.h>
+
+#define NDEBUG
+#include <internal/debug.h>
+
+/* GLOBALS ******************************************************************/
+
+#ifdef DBG
+
+typedef struct _SYMBOLFILE_HEADER {
+ unsigned long StabsOffset;
+ unsigned long StabsLength;
+ unsigned long StabstrOffset;
+ unsigned long StabstrLength;
+} SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER;
+
+typedef struct _IMAGE_SYMBOL_INFO_CACHE {
+ LIST_ENTRY ListEntry;
+ UNICODE_STRING FullName;
+ PVOID FileBuffer;
+ PVOID SymbolsBase;
+ ULONG SymbolsLength;
+ PVOID SymbolStringsBase;
+ ULONG SymbolStringsLength;
+} IMAGE_SYMBOL_INFO_CACHE, *PIMAGE_SYMBOL_INFO_CACHE;
+
+
+typedef struct _STAB_ENTRY {
+ unsigned long n_strx; /* index into string table of name */
+ unsigned char n_type; /* type of symbol */
+ unsigned char n_other; /* misc info (usually empty) */
+ unsigned short n_desc; /* description field */
+ unsigned long n_value; /* value of symbol */
+} _STAB_ENTRY, *PSTAB_ENTRY;
+
+/*
+ * Desc - Line number
+ * Value - Relative virtual address
+ */
+#define N_FUN 0x24
+
+/*
+ * Desc - Line number
+ * Value - Relative virtual address
+ */
+#define N_SLINE 0x44
+
+/*
+ * String - First containing a '/' is the compillation directory (CD)
+ * Not containing a '/' is a source file relative to CD
+ */
+#define N_SO 0x64
+
+LIST_ENTRY SymbolListHead;
+
+#endif /* DBG */
+
+#ifdef DBG
+
+NTSTATUS
+LdrGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo,
+ IN ULONG_PTR RelativeAddress,
+ OUT PULONG LineNumber,
+ OUT PCH FileName OPTIONAL,
+ OUT PCH FunctionName OPTIONAL);
+
+#endif /* DBG */
+
+/* FUNCTIONS ****************************************************************/
+
+STATIC BOOLEAN
+print_user_address(PVOID address)
+{
+ PLIST_ENTRY current_entry;
+ PLDR_MODULE current;
+ PEPROCESS CurrentProcess;
+ PPEB Peb = NULL;
+ ULONG_PTR RelativeAddress;
+#ifdef DBG
+ NTSTATUS Status;
+ ULONG LineNumber;
+ CHAR FileName[256];
+ CHAR FunctionName[256];
+#endif
+
+ CurrentProcess = PsGetCurrentProcess();
+ if (NULL != CurrentProcess)
+ {
+ Peb = CurrentProcess->Peb;
+ }
+
+ if (NULL == Peb)
+ {
+ DbgPrint("<%x>", address);
+ return(TRUE);
+ }
+
+ current_entry = Peb->Ldr->InLoadOrderModuleList.Flink;
+
+ while (current_entry != &Peb->Ldr->InLoadOrderModuleList &&
+ current_entry != NULL)
+ {
+ current =
+ CONTAINING_RECORD(current_entry, LDR_MODULE, InLoadOrderModuleList);
+
+ if (address >= (PVOID)current->BaseAddress &&
+ address < (PVOID)(current->BaseAddress + current->SizeOfImage))
+ {
+ RelativeAddress = (ULONG_PTR) address - (ULONG_PTR)current->BaseAddress;
+#ifdef DBG
+ Status = LdrGetAddressInformation(¤t->SymbolInfo,
+ RelativeAddress,
+ &LineNumber,
+ FileName,
+ FunctionName);
+ if (NT_SUCCESS(Status))
+ {
+ DbgPrint("<%wZ: %x (%s:%d (%s))>",
+ ¤t->BaseDllName, RelativeAddress, FileName, LineNumber, FunctionName);
+ }
+ else
+ {
+ DbgPrint("<%wZ: %x>", ¤t->BaseDllName, RelativeAddress);
+ }
+#else /* !DBG */
+ DbgPrint("<%wZ: %x>", ¤t->BaseDllName, RelativeAddress);
+#endif /* !DBG */
+
+ return(TRUE);
+ }
+
+ current_entry = current_entry->Flink;
+ }
+ return(FALSE);
+}
+
+STATIC BOOLEAN
+print_address(PVOID address)
+{
+ PLIST_ENTRY current_entry;
+ MODULE_TEXT_SECTION* current;
+ extern LIST_ENTRY ModuleTextListHead;
+ ULONG_PTR RelativeAddress;
+#ifdef DBG
+ NTSTATUS Status;
+ ULONG LineNumber;
+ CHAR FileName[256];
+ CHAR FunctionName[256];
+#endif
+
+ current_entry = ModuleTextListHead.Flink;
+
+ while (current_entry != &ModuleTextListHead &&
+ current_entry != NULL)
+ {
+ current =
+ CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
+
+ if (address >= (PVOID)current->Base &&
+ address < (PVOID)(current->Base + current->Length))
+ {
+ RelativeAddress = (ULONG_PTR) address - current->Base;
+#ifdef kDBG
+ Status = LdrGetAddressInformation(¤t->SymbolInfo,
+ RelativeAddress,
+ &LineNumber,
+ FileName,
+ FunctionName);
+ if (NT_SUCCESS(Status))
+ {
+ DbgPrint("<%ws: %x (%s:%d (%s))>",
+ current->Name, RelativeAddress, FileName, LineNumber, FunctionName);
+ }
+ else
+ {
+ DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
+ }
+#else /* !DBG */
+ DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
+#endif /* !DBG */
+ return(TRUE);
+ }
+ current_entry = current_entry->Flink;
+ }
+ return(FALSE);
+}
+
+#ifdef DBG
+
+VOID
+PiFreeSymbols(PPEB Peb)
+{
+ PLIST_ENTRY CurrentEntry;
+ PLDR_MODULE Current;
+ PIMAGE_SYMBOL_INFO SymbolInfo;
+
+ assert (Peb);
+ assert (Peb->Ldr);
+
+ CurrentEntry = Peb->Ldr->InLoadOrderModuleList.Flink;
+ while (CurrentEntry != &Peb->Ldr->InLoadOrderModuleList &&
+ CurrentEntry != NULL)
+ {
+ Current = CONTAINING_RECORD(CurrentEntry, LDR_MODULE,
+ InLoadOrderModuleList);
+
+ SymbolInfo = &Current->SymbolInfo;
+ LdrUnloadModuleSymbols(SymbolInfo);
+
+ CurrentEntry = CurrentEntry->Flink;
+ }
+}
+
+VOID
+KdbLdrInit(VOID)
+{
+#ifdef DBG
+ RtlZeroMemory(&NtoskrnlTextSection.SymbolInfo, sizeof(NtoskrnlTextSection.SymbolInfo));
+ NtoskrnlTextSection.SymbolInfo.ImageBase = OptionalHeader->ImageBase;
+ NtoskrnlTextSection.SymbolInfo.ImageSize = NtoskrnlTextSection.Length;
+#endif
+
+#ifdef DBG
+ RtlZeroMemory(&LdrHalTextSection.SymbolInfo, sizeof(LdrHalTextSection.SymbolInfo));
+ LdrHalTextSection.SymbolInfo.ImageBase = OptionalHeader->ImageBase;
+ LdrHalTextSection.SymbolInfo.ImageSize = LdrHalTextSection.Length;
+#endif
+
+#ifdef DBG
+ InitializeListHead(&SymbolListHead);
+#endif
+}
+
+#ifdef DBG
+
+VOID
+LdrpParseImageSymbols(PIMAGE_SYMBOL_INFO SymbolInfo)
+/* Note: It is important that the symbol strings buffer not be released after
+ this function is called because the strings are still referenced */
+{
+ PSYMBOL CurrentFileNameSymbol;
+ PSYMBOL CurrentFunctionSymbol;
+ PSYMBOL CurrentLineNumberSymbol;
+ PSYMBOL Symbol;
+ PSTAB_ENTRY StabEntry;
+ PVOID StabsEnd;
+ PCHAR String;
+ ULONG_PTR FunRelativeAddress;
+ ULONG FunLineNumber;
+ ULONG_PTR ImageBase;
+
+ assert(SymbolInfo);
+
+ DPRINT("Parsing symbols.\n");
+
+ SymbolInfo->FileNameSymbols.SymbolCount = 0;
+ SymbolInfo->FileNameSymbols.Symbols = NULL;
+ SymbolInfo->FunctionSymbols.SymbolCount = 0;
+ SymbolInfo->FunctionSymbols.Symbols = NULL;
+ SymbolInfo->LineNumberSymbols.SymbolCount = 0;
+ SymbolInfo->LineNumberSymbols.Symbols = NULL;
+ StabsEnd = SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength;
+ StabEntry = (PSTAB_ENTRY) SymbolInfo->SymbolsBase;
+ ImageBase = SymbolInfo->ImageBase;
+ FunRelativeAddress = 0;
+ FunLineNumber = 0;
+ CurrentFileNameSymbol = NULL;
+ CurrentFunctionSymbol = NULL;
+ CurrentLineNumberSymbol = NULL;
+ while ((ULONG_PTR) StabEntry < (ULONG_PTR) StabsEnd)
+ {
+ Symbol = NULL;
+
+ if (StabEntry->n_type == N_FUN)
+ {
+ if (StabEntry->n_desc > 0)
+ {
+ assert(StabEntry->n_value >= ImageBase);
+
+ FunRelativeAddress = StabEntry->n_value - ImageBase;
+ FunLineNumber = StabEntry->n_desc;
+
+ Symbol = ExAllocatePool(NonPagedPool, sizeof(SYMBOL));
+ assert(Symbol);
+ Symbol->Next = NULL;
+ Symbol->SymbolType = ST_FUNCTION;
+ Symbol->RelativeAddress = FunRelativeAddress;
+ Symbol->LineNumber = FunLineNumber;
+ String = (PCHAR)SymbolInfo->SymbolStringsBase + StabEntry->n_strx;
+ RtlInitAnsiString(&Symbol->Name, String);
+
+ DPRINT("FUN found. '%s' %d @ %x\n",
+ Symbol->Name.Buffer, FunLineNumber, FunRelativeAddress);
+ }
+ }
+ else if (StabEntry->n_type == N_SLINE)
+ {
+ Symbol = ExAllocatePool(NonPagedPool, sizeof(SYMBOL));
+ assert(Symbol);
+ Symbol->Next = NULL;
+ Symbol->SymbolType = ST_LINENUMBER;
+ Symbol->RelativeAddress = FunRelativeAddress + StabEntry->n_value;
+ Symbol->LineNumber = StabEntry->n_desc;
+
+ DPRINT("SLINE found. %d @ %x\n",
+ Symbol->LineNumber, Symbol->RelativeAddress);
+ }
+ else if (StabEntry->n_type == N_SO)
+ {
+ Symbol = ExAllocatePool(NonPagedPool, sizeof(SYMBOL));
+ assert(Symbol);
+ Symbol->Next = NULL;
+ Symbol->SymbolType = ST_FILENAME;
+ Symbol->RelativeAddress = StabEntry->n_value - ImageBase;
+ Symbol->LineNumber = 0;
+ String = (PCHAR)SymbolInfo->SymbolStringsBase + StabEntry->n_strx;
+ RtlInitAnsiString(&Symbol->Name, String);
+
+ DPRINT("SO found. '%s' @ %x\n",
+ Symbol->Name.Buffer, Symbol->RelativeAddress);
+ }
+
+ if (Symbol != NULL)
+ {
+ switch (Symbol->SymbolType)
+ {
+ case ST_FILENAME:
+ if (SymbolInfo->FileNameSymbols.Symbols == NULL)
+ SymbolInfo->FileNameSymbols.Symbols = Symbol;
+ else
+ CurrentFileNameSymbol->Next = Symbol;
+
+ CurrentFileNameSymbol = Symbol;
+
+ SymbolInfo->FileNameSymbols.SymbolCount++;
+ break;
+ case ST_FUNCTION:
+ if (SymbolInfo->FunctionSymbols.Symbols == NULL)
+ SymbolInfo->FunctionSymbols.Symbols = Symbol;
+ else
+ CurrentFunctionSymbol->Next = Symbol;
+
+ CurrentFunctionSymbol = Symbol;
+
+ SymbolInfo->FunctionSymbols.SymbolCount++;
+ break;
+ case ST_LINENUMBER:
+ if (SymbolInfo->LineNumberSymbols.Symbols == NULL)
+ SymbolInfo->LineNumberSymbols.Symbols = Symbol;
+ else
+ CurrentLineNumberSymbol->Next = Symbol;
+
+ CurrentLineNumberSymbol = Symbol;
+
+ SymbolInfo->LineNumberSymbols.SymbolCount++;
+ break;
+ }
+ }
+
+ StabEntry++;
+ }
+}
+
+static NTSTATUS
+LdrpGetFileName(IN PIMAGE_SYMBOL_INFO SymbolInfo,
+ IN ULONG_PTR RelativeAddress,
+ OUT PCH FileName)
+{
+ PSYMBOL NextSymbol;
+ ULONG_PTR NextAddress;
+ PSYMBOL Symbol;
+
+ Symbol = SymbolInfo->FileNameSymbols.Symbols;
+ while (Symbol != NULL)
+ {
+ NextSymbol = Symbol->Next;
+ if (NextSymbol != NULL)
+ NextAddress = NextSymbol->RelativeAddress;
+ else
+ NextAddress = SymbolInfo->ImageSize;
+
+ DPRINT("FN SEARCH: Type %d RelativeAddress %x >= Symbol->RelativeAddress %x < NextAddress %x\n",
+ Symbol->SymbolType, RelativeAddress, Symbol->RelativeAddress, NextAddress);
+
+ if ((Symbol->SymbolType == ST_FILENAME) &&
+ (RelativeAddress >= Symbol->RelativeAddress) &&
+ (RelativeAddress < NextAddress))
+ {
+ DPRINT("FN found\n");
+ strcpy(FileName, Symbol->Name.Buffer);
+ return STATUS_SUCCESS;
+ }
+ Symbol = NextSymbol;
+ }
+
+ DPRINT("FN not found\n");
+
+ return STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS
+LdrpGetFunctionName(IN PIMAGE_SYMBOL_INFO SymbolInfo,
+ IN ULONG_PTR RelativeAddress,
+ OUT PCH FunctionName)
+{
+ PSYMBOL NextSymbol;
+ ULONG_PTR NextAddress;
+ PSYMBOL Symbol;
+
+ Symbol = SymbolInfo->FunctionSymbols.Symbols;
+ while (Symbol != NULL)
+ {
+ NextSymbol = Symbol->Next;
+ if (NextSymbol != NULL)
+ NextAddress = NextSymbol->RelativeAddress;
+ else
+ NextAddress = SymbolInfo->ImageSize;
+
+ DPRINT("FUN SEARCH: Type %d RelativeAddress %x >= Symbol->RelativeAddress %x < NextAddress %x\n",
+ Symbol->SymbolType, RelativeAddress, Symbol->RelativeAddress, NextAddress);
+
+ if ((Symbol->SymbolType == ST_FUNCTION) &&
+ (RelativeAddress >= Symbol->RelativeAddress) &&
+ (RelativeAddress < NextAddress))
+ {
+ PCHAR ExtraInfo;
+ ULONG Length;
+
+ DPRINT("FUN found\n");
+
+ /* Remove the extra information from the function name */
+ ExtraInfo = strchr(Symbol->Name.Buffer, ':');
+ if (ExtraInfo != NULL)
+ Length = ExtraInfo - Symbol->Name.Buffer;
+ else
+ Length = strlen(Symbol->Name.Buffer);
+
+ strncpy(FunctionName, Symbol->Name.Buffer, Length);
+ return STATUS_SUCCESS;
+ }
+ Symbol = NextSymbol;
+ }
+
+ DPRINT("FUN not found\n");
+
+ return STATUS_UNSUCCESSFUL;
+}
+
+static NTSTATUS
+LdrpGetLineNumber(IN PIMAGE_SYMBOL_INFO SymbolInfo,
+ IN ULONG_PTR RelativeAddress,
+ OUT PULONG LineNumber)
+{
+ PSYMBOL NextSymbol;
+ ULONG_PTR NextAddress;
+ PSYMBOL Symbol;
+
+ Symbol = SymbolInfo->LineNumberSymbols.Symbols;
+ while (Symbol != NULL)
+ {
+ NextSymbol = Symbol->Next;
+ if (NextSymbol != NULL)
+ NextAddress = NextSymbol->RelativeAddress;
+ else
+ NextAddress = SymbolInfo->ImageSize;
+
+ DPRINT("LN SEARCH: Type %d RelativeAddress %x >= Symbol->RelativeAddress %x < NextAddress %x\n",
+ Symbol->SymbolType, RelativeAddress, Symbol->RelativeAddress, NextAddress);
+
+ if ((Symbol->SymbolType == ST_LINENUMBER) &&
+ (RelativeAddress >= Symbol->RelativeAddress) &&
+ (RelativeAddress < NextAddress))
+ {
+ DPRINT("LN found\n");
+ *LineNumber = Symbol->LineNumber;
+ return STATUS_SUCCESS;
+ }
+ Symbol = NextSymbol;
+ }
+
+ DPRINT("LN not found\n");
+
+ return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+LdrGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo,
+ IN ULONG_PTR RelativeAddress,
+ OUT PULONG LineNumber,
+ OUT PCH FileName OPTIONAL,
+ OUT PCH FunctionName OPTIONAL)
+{
+ NTSTATUS Status;
+
+ *LineNumber = 0;
+
+ DPRINT("RelativeAddress %p\n", RelativeAddress);
+
+ if (RelativeAddress >= SymbolInfo->ImageSize)
+ {
+ DPRINT("Address is not within .text section. RelativeAddress %p Length 0x%x\n",
+ RelativeAddress, SymbolInfo->ImageSize);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (!AreSymbolsParsed(SymbolInfo))
+ {
+ LdrpParseImageSymbols(SymbolInfo);
+ }
+
+ Status = LdrpGetLineNumber(SymbolInfo, RelativeAddress, LineNumber);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ if (FileName)
+ {
+ Status = LdrpGetFileName(SymbolInfo, RelativeAddress, FileName);
+ if (!NT_SUCCESS(Status))
+ {
+ strcpy(FileName, "");
+ }
+ }
+
+ if (FunctionName)
+ {
+ Status = LdrpGetFunctionName(SymbolInfo, RelativeAddress, FunctionName);
+ if (!NT_SUCCESS(Status))
+ {
+ strcpy(FunctionName, "");
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+LdrpLoadModuleSymbols(PUNICODE_STRING FileName,
+ PIMAGE_SYMBOL_INFO SymbolInfo)
+{
+ FILE_STANDARD_INFORMATION FileStdInfo;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ WCHAR TmpFileName[MAX_PATH];
+ UNICODE_STRING SymFileName;
+ LPWSTR Start, Ext;
+ HANDLE FileHandle;
+ PVOID FileBuffer;
+ NTSTATUS Status;
+ ULONG Length;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PSYMBOLFILE_HEADER SymbolFileHeader;
+
+ /* Get the path to the symbol store */
+ wcscpy(TmpFileName, L"\\SystemRoot\\symbols\\");
+
+ /* Get the symbol filename from the module name */
+ Start = wcsrchr(FileName->Buffer, L'\\');
+ if (Start == NULL)
+ Start = FileName->Buffer;
+ else
+ Start++;
+
+ Ext = wcsrchr(FileName->Buffer, L'.');
+ if (Ext != NULL)
+ Length = Ext - Start;
+ else
+ Length = wcslen(Start);
+
+ wcsncat(TmpFileName, Start, Length);
+ wcscat(TmpFileName, L".sym");
+ RtlInitUnicodeString(&SymFileName, TmpFileName);
+
+ /* Open the file */
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SymFileName,
+ 0,
+ NULL,
+ NULL);
+
+ Status = ZwOpenFile(&FileHandle,
+ FILE_ALL_ACCESS,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ 0,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Could not open symbol file: %wZ\n", &SymFileName);
+ return;
+ }
+
+ CPRINT("Loading symbols from %wZ...\n", &SymFileName);
+
+ /* Get the size of the file */
+ Status = ZwQueryInformationFile(FileHandle,
+ &IoStatusBlock,
+ &FileStdInfo,
+ sizeof(FileStdInfo),
+ FileStandardInformation);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Could not get file size\n");
+ ZwClose(FileHandle);
+ return;
+ }
+
+ /* Allocate nonpageable memory for symbol file */
+ FileBuffer = ExAllocatePool(NonPagedPool,
+ FileStdInfo.EndOfFile.u.LowPart);
+
+ if (FileBuffer == NULL)
+ {
+ DPRINT("Could not allocate memory for symbol file\n");
+ ZwClose(FileHandle);
+ return;
+ }
+
+ /* Load file into memory chunk */
+ Status = ZwReadFile(FileHandle,
+ 0, 0, 0,
+ &IoStatusBlock,
+ FileBuffer,
+ FileStdInfo.EndOfFile.u.LowPart,
+ 0, 0);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Could not read symbol file into memory (Status 0x%x)\n", Status);
+ ExFreePool(FileBuffer);
+ ZwClose(FileHandle);
+ return;
+ }
+
+ ZwClose(FileHandle);
+
+ SymbolFileHeader = (PSYMBOLFILE_HEADER) FileBuffer;
+ SymbolInfo->FileBuffer = FileBuffer;
+ SymbolInfo->SymbolsBase = FileBuffer + SymbolFileHeader->StabsOffset;
+ SymbolInfo->SymbolsLength = SymbolFileHeader->StabsLength;
+ SymbolInfo->SymbolStringsBase = FileBuffer + SymbolFileHeader->StabstrOffset;
+ SymbolInfo->SymbolStringsLength = SymbolFileHeader->StabstrLength;
+}
+
+
+VOID
+LdrUnloadModuleSymbols(PIMAGE_SYMBOL_INFO SymbolInfo)
+{
+ PSYMBOL NextSymbol;
+ PSYMBOL Symbol;
+
+ DPRINT("Unloading symbols\n");
+
+ if (SymbolInfo != NULL)
+ {
+ Symbol = SymbolInfo->FileNameSymbols.Symbols;
+ while (Symbol != NULL)
+ {
+ NextSymbol = Symbol->Next;
+ RtlFreeAnsiString(&Symbol->Name);
+ ExFreePool(Symbol);
+ Symbol = NextSymbol;
+ }
+
+ SymbolInfo->FileNameSymbols.SymbolCount = 0;
+ SymbolInfo->FileNameSymbols.Symbols = NULL;
+
+ Symbol = SymbolInfo->FunctionSymbols.Symbols;
+ while (Symbol != NULL)
+ {
+ NextSymbol = Symbol->Next;
+ RtlFreeAnsiString(&Symbol->Name);
+ ExFreePool(Symbol);
+ Symbol = NextSymbol;
+ }
+
+ SymbolInfo->FunctionSymbols.SymbolCount = 0;
+ SymbolInfo->FunctionSymbols.Symbols = NULL;
+
+ Symbol = SymbolInfo->LineNumberSymbols.Symbols;
+ while (Symbol != NULL)
+ {
+ NextSymbol = Symbol->Next;
+ RtlFreeAnsiString(&Symbol->Name);
+ ExFreePool(Symbol);
+ Symbol = NextSymbol;
+ }
+
+ SymbolInfo->LineNumberSymbols.SymbolCount = 0;
+ SymbolInfo->LineNumberSymbols.Symbols = NULL;
+#if 0
+ /* Don't free buffers because we cache symbol buffers
+ (eg. they are shared across processes) */
+ /* FIXME: We can free them if we do reference counting */
+ if (SymbolInfo->FileBuffer != NULL)
+ {
+ ExFreePool(SymbolInfo->FileBuffer);
+ SymbolInfo->FileBuffer = NULL;
+ SymbolInfo->SymbolsBase = NULL;
+ SymbolInfo->SymbolsLength = 0;
+ }
+#endif
+ }
+}
+
+
+PIMAGE_SYMBOL_INFO_CACHE
+LdrpLookupUserSymbolInfo(PLDR_MODULE LdrModule)
+{
+ PIMAGE_SYMBOL_INFO_CACHE Current;
+ PLIST_ENTRY CurrentEntry;
+ KIRQL Irql;
+
+ DPRINT("Searching symbols for %S\n", LdrModule->FullDllName.Buffer);
+
+ KeAcquireSpinLock(&ModuleListLock,&Irql);
+
+ CurrentEntry = SymbolListHead.Flink;
+ while (CurrentEntry != (&SymbolListHead))
+ {
+ Current = CONTAINING_RECORD(CurrentEntry, IMAGE_SYMBOL_INFO_CACHE, ListEntry);
+
+ if (RtlEqualUnicodeString(&Current->FullName, &LdrModule->FullDllName, TRUE))
+ {
+ KeReleaseSpinLock(&ModuleListLock, Irql);
+ return Current;
+ }
+
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ KeReleaseSpinLock(&ModuleListLock, Irql);
+
+ return(NULL);
+}
+
+
+VOID
+LdrLoadUserModuleSymbols(PLDR_MODULE LdrModule)
+{
+ PIMAGE_SYMBOL_INFO_CACHE CacheEntry;
+
+ DPRINT("LdrModule %p\n", LdrModule);
+
+ RtlZeroMemory(&LdrModule->SymbolInfo, sizeof(LdrModule->SymbolInfo));
+ LdrModule->SymbolInfo.ImageBase = (ULONG_PTR) LdrModule->BaseAddress;
+ LdrModule->SymbolInfo.ImageSize = LdrModule->SizeOfImage;
+
+ CacheEntry = LdrpLookupUserSymbolInfo(LdrModule);
+ if (CacheEntry != NULL)
+ {
+ DPRINT("Symbol cache hit for %S\n", CacheEntry->FullName.Buffer);
+
+ LdrModule->SymbolInfo.FileBuffer = CacheEntry->FileBuffer;
+ LdrModule->SymbolInfo.SymbolsBase = CacheEntry->SymbolsBase;
+ LdrModule->SymbolInfo.SymbolsLength = CacheEntry->SymbolsLength;
+ LdrModule->SymbolInfo.SymbolStringsBase = CacheEntry->SymbolStringsBase;
+ LdrModule->SymbolInfo.SymbolStringsLength = CacheEntry->SymbolStringsLength;
+ }
+ else
+ {
+ CacheEntry = ExAllocatePool(NonPagedPool, sizeof(IMAGE_SYMBOL_INFO_CACHE));
+ assert(CacheEntry);
+ RtlZeroMemory(CacheEntry, sizeof(IMAGE_SYMBOL_INFO_CACHE));
+ RtlCreateUnicodeString(&CacheEntry->FullName, LdrModule->FullDllName.Buffer);
+ assert(CacheEntry->FullName.Buffer);
+ LdrpLoadModuleSymbols(&LdrModule->FullDllName, &LdrModule->SymbolInfo);
+ InsertTailList(&SymbolListHead, &CacheEntry->ListEntry);
+ }
+}
+
+#endif /* DBG */
+
+VOID
+KdbLoadDriver(VOID)
+{
+#ifdef DBG
+ /* Load symbols for the image if available */
+ LdrpLoadModuleSymbols(Filename, &Module->TextSection->SymbolInfo);
+#endif /* DBG */
+}
+
+VOID
+KdbUnloadDriver(VOID)
+{
+#ifdef DBG
+ /* Unload symbols for module if available */
+ LdrUnloadModuleSymbols(&ModuleObject->TextSection->SymbolInfo);
+#endif /* DBG */
+}
+
+VOID
+KdbInitializeDriver(VOID)
+{
+#ifdef DBG
+ PSYMBOLFILE_HEADER SymbolFileHeader;
+ PIMAGE_SYMBOL_INFO SymbolInfo;
+#endif /* DBG */
+
+#ifdef DBG
+ CHAR TmpBaseName[MAX_PATH];
+ CHAR TmpFileName[MAX_PATH];
+ ANSI_STRING AnsiString;
+#endif /* DBG */
+
+#ifdef DBG
+
+ if ((FileExt != NULL) && (strcmp(FileExt, ".sym") == 0))
+ {
+ DPRINT("Module %s is a symbol file\n", FileName);
+
+ strncpy(TmpBaseName, FileName, Length);
+ TmpBaseName[Length] = '\0';
+
+ DPRINT("base: %s (Length %d)\n", TmpBaseName, Length);
+
+ strcpy(TmpFileName, TmpBaseName);
+ strcat(TmpFileName, ".sys");
+ RtlInitAnsiString(&AnsiString, TmpFileName);
+
+ RtlAnsiStringToUnicodeString(&ModuleName, &AnsiString, TRUE);
+ ModuleObject = LdrGetModuleObject(&ModuleName);
+ RtlFreeUnicodeString(&ModuleName);
+ if (ModuleObject == NULL)
+ {
+ strcpy(TmpFileName, TmpBaseName);
+ strcat(TmpFileName, ".exe");
+ RtlInitAnsiString(&AnsiString, TmpFileName);
+ RtlAnsiStringToUnicodeString(&ModuleName, &AnsiString, TRUE);
+ ModuleObject = LdrGetModuleObject(&ModuleName);
+ RtlFreeUnicodeString(&ModuleName);
+ }
+ if (ModuleObject != NULL)
+ {
+ SymbolInfo = (PIMAGE_SYMBOL_INFO) &ModuleObject->TextSection->SymbolInfo;
+ SymbolFileHeader = (PSYMBOLFILE_HEADER) ModuleLoadBase;
+ SymbolInfo->FileBuffer = ModuleLoadBase;
+ SymbolInfo->SymbolsBase = ModuleLoadBase + SymbolFileHeader->StabsOffset;
+ SymbolInfo->SymbolsLength = SymbolFileHeader->StabsLength;
+ SymbolInfo->SymbolStringsBase = ModuleLoadBase + SymbolFileHeader->StabstrOffset;
+ SymbolInfo->SymbolStringsLength = SymbolFileHeader->StabstrLength;
+ }
+
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ DPRINT("Module %s is non-symbol file\n", FileName);
+ }
+
+#endif /* !DBG */
+
+#ifdef DBG
+ RtlZeroMemory(&ModuleTextSection->SymbolInfo, sizeof(ModuleTextSection->SymbolInfo));
+ ModuleTextSection->SymbolInfo.ImageBase = PEOptionalHeader->ImageBase;
+ ModuleTextSection->SymbolInfo.ImageSize = ModuleTextSection->Length;
+#endif /* DBG */
+}
+
+#endif /* DBG */