KDB stabs file.
authorDavid Welch <welch@cwcom.net>
Wed, 17 Jul 2002 22:57:18 +0000 (22:57 +0000)
committerDavid Welch <welch@cwcom.net>
Wed, 17 Jul 2002 22:57:18 +0000 (22:57 +0000)
svn path=/trunk/; revision=3246

reactos/ntoskrnl/dbg/kdb_stabs.c [new file with mode: 0644]

diff --git a/reactos/ntoskrnl/dbg/kdb_stabs.c b/reactos/ntoskrnl/dbg/kdb_stabs.c
new file mode 100644 (file)
index 0000000..46225b2
--- /dev/null
@@ -0,0 +1,899 @@
+/*
+ *  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(&current->SymbolInfo,
+              RelativeAddress,
+              &LineNumber,
+              FileName,
+              FunctionName);
+            if (NT_SUCCESS(Status))
+              {
+                DbgPrint("<%wZ: %x (%s:%d (%s))>",
+                  &current->BaseDllName, RelativeAddress, FileName, LineNumber, FunctionName);
+              }
+            else
+             {
+               DbgPrint("<%wZ: %x>", &current->BaseDllName, RelativeAddress);
+             }
+#else /* !DBG */
+             DbgPrint("<%wZ: %x>", &current->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(&current->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 */