Compilation bug fixed (due to having used an "unknown" field in the
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
index 55e7fbc..085f831 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: loader.c,v 1.64 2000/10/08 16:32:53 dwelch Exp $
+/* $Id: loader.c,v 1.74 2001/04/23 22:00:28 ea Exp $
  * 
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
@@ -7,6 +7,7 @@
  * PROGRAMMERS:     Jean Michault
  *                  Rex Jolliff (rex@lvcablemodem.com)
  *                  Jason Filby (jasonfilby@yahoo.com)
+ *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
  * UPDATE HISTORY:
  *   DW   22/05/98   Created
  *   RJJ  10/12/98   Completed image loader function and added hooks for MZ/PE
  *   JM   14/12/98   Built initial PE user module loader
  *   RJJ  06/03/99   Moved user PE loader into NTDLL
  *   JF   26/01/2000 Recoded some parts to retrieve export details correctly
- *   DW   27/06/00   Removed redundant header files
+ *   DW   27/06/2000 Removed redundant header files
+ *   CSH  11/04/2001 Added automatic loading of module symbols if they exist
  */
 
+
 /* INCLUDES *****************************************************************/
 
 #include <limits.h>
 #include <ddk/ntddk.h>
+#include <internal/config.h>
 #include <internal/module.h>
 #include <internal/ntoskrnl.h>
 #include <internal/mm.h>
-#include <internal/mmhal.h>
 #include <internal/ob.h>
 #include <internal/ps.h>
-#include <string.h>
-#include <internal/string.h>
+#include <internal/ldr.h>
+#include <internal/pool.h>
 
 #define NDEBUG
 #include <internal/debug.h>
@@ -46,11 +49,14 @@ NTSTATUS IoInitializeDriver(PDRIVER_INITIALIZE DriverEntry);
 
 LIST_ENTRY ModuleListHead;
 POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
+LIST_ENTRY ModuleTextListHead;
+STATIC MODULE_TEXT_SECTION NtoskrnlTextSection;
+/* STATIC MODULE_TEXT_SECTION HalTextSection; */
 
-/* FORWARD DECLARATIONS ******************************************************/
+#define TAG_DRIVER_MEM  TAG('D', 'R', 'V', 'M')
+#define TAG_SYM_BUF     TAG('S', 'Y', 'M', 'B')
 
-NTSTATUS LdrLoadDriver(PUNICODE_STRING Filename);
-NTSTATUS LdrProcessDriver(PVOID ModuleLoadBase);
+/* FORWARD DECLARATIONS ******************************************************/
 
 PMODULE_OBJECT  LdrLoadModule(PUNICODE_STRING Filename);
 PMODULE_OBJECT  LdrProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING ModuleName);
@@ -60,26 +66,79 @@ static NTSTATUS LdrCreateModule(PVOID ObjectBody,
                                 PVOID Parent,
                                 PWSTR RemainingPath,
                                 POBJECT_ATTRIBUTES ObjectAttributes);
+static VOID LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
+                                   PUNICODE_STRING FullName);
 
 /*  PE Driver load support  */
-static PMODULE_OBJECT  LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING ModuleName);
+static PMODULE_OBJECT  LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING FileName);
 static PVOID  LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
                                     char *Name,
                                     unsigned short Hint);
-#if 0
-static unsigned int LdrGetKernelSymbolAddr(char *Name);
-#endif
-static PIMAGE_SECTION_HEADER LdrPEGetEnclosingSectionHeader(DWORD  RVA,
-                                                            PMODULE_OBJECT  ModuleObject);
+static PMODULE_OBJECT LdrPEGetModuleObject(PUNICODE_STRING ModuleName);
+static PVOID LdrPEFixupForward(PCHAR ForwardName);
+
 
 /* FUNCTIONS *****************************************************************/
 
+VOID
+LdrInitDebug(PLOADER_MODULE Module, PWCH Name)
+{
+  PLIST_ENTRY current_entry;
+  MODULE_TEXT_SECTION* current;
+
+  current_entry = ModuleTextListHead.Flink;
+  while (current_entry != &ModuleTextListHead)
+    {
+      current = 
+       CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
+      if (wcscmp(current->Name, Name) == 0)
+       {
+         break;
+       }
+      current_entry = current_entry->Flink;
+    }
+
+  if (current_entry == &ModuleTextListHead)
+    {
+      return;
+    }
+  
+  current->SymbolsBase = (PVOID)Module->ModStart;
+  current->SymbolsLength = Module->ModEnd - Module->ModStart;
+}
+
+VOID
+LdrInit1(VOID)
+{
+  PIMAGE_DOS_HEADER DosHeader;
+  PIMAGE_FILE_HEADER FileHeader;
+  PIMAGE_OPTIONAL_HEADER OptionalHeader;
+  PIMAGE_SECTION_HEADER SectionList;
+
+  InitializeListHead(&ModuleTextListHead);
+
+  DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
+  FileHeader =
+    (PIMAGE_FILE_HEADER) ((DWORD)KERNEL_BASE + 
+                         DosHeader->e_lfanew + sizeof(ULONG));
+  OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
+    ((DWORD)FileHeader + sizeof(IMAGE_FILE_HEADER));
+  SectionList = (PIMAGE_SECTION_HEADER)
+    ((DWORD)OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
+  NtoskrnlTextSection.Base = KERNEL_BASE;
+  NtoskrnlTextSection.Length = SectionList[0].Misc.VirtualSize +
+    SectionList[0].VirtualAddress;
+  NtoskrnlTextSection.Name = L"ntoskrnl.exe";
+  NtoskrnlTextSection.SymbolsBase = NULL;
+  NtoskrnlTextSection.SymbolsLength = 0;
+  InsertTailList(&ModuleTextListHead, &NtoskrnlTextSection.ListEntry);
+}
+
 VOID LdrInitModuleManagement(VOID)
 {
   HANDLE DirHandle, ModuleHandle;
   NTSTATUS Status;
   WCHAR NameBuffer[60];
-  ANSI_STRING AnsiString;
   UNICODE_STRING ModuleName;
   OBJECT_ATTRIBUTES ObjectAttributes;
   PIMAGE_DOS_HEADER DosHeader;
@@ -87,6 +146,7 @@ VOID LdrInitModuleManagement(VOID)
 
   /*  Register the process object type  */
   IoDriverObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
+  IoDriverObjectType->Tag = TAG('D', 'R', 'V', 'T');
   IoDriverObjectType->TotalObjects = 0;
   IoDriverObjectType->TotalHandles = 0;
   IoDriverObjectType->MaxObjects = ULONG_MAX;
@@ -102,8 +162,7 @@ VOID LdrInitModuleManagement(VOID)
   IoDriverObjectType->QueryName = NULL;
   IoDriverObjectType->OkayToClose = NULL;
   IoDriverObjectType->Create = LdrCreateModule;
-  RtlInitAnsiString(&AnsiString, "Module");
-  RtlAnsiStringToUnicodeString(&IoDriverObjectType->TypeName, &AnsiString, TRUE);
+  RtlInitUnicodeString(&IoDriverObjectType->TypeName, L"Driver");
 
   /*  Create Modules object directory  */
   wcscpy(NameBuffer, MODULE_ROOT_NAME);
@@ -139,13 +198,18 @@ VOID LdrInitModuleManagement(VOID)
                                 IoDriverObjectType);
   assert(ModuleObject != NULL);
 
-  InitializeListHead(&ModuleListHead);
+   InitializeListHead(&ModuleListHead);
+
+   /*  Initialize ModuleObject data  */
+   ModuleObject->Base = (PVOID) KERNEL_BASE;
+   ModuleObject->Flags = MODULE_FLAG_PE;
+   InsertTailList(&ModuleListHead,
+                 &ModuleObject->ListEntry);
+   RtlCreateUnicodeString(&ModuleObject->FullName,
+                         L"ntoskrnl.exe");
+   LdrpBuildModuleBaseName(&ModuleObject->BaseName,
+                          &ModuleObject->FullName);
 
-  /*  Initialize ModuleObject data  */
-  ModuleObject->Base = (PVOID) KERNEL_BASE;
-  ModuleObject->Flags = MODULE_FLAG_PE;
-  InsertTailList(&ModuleListHead, &ModuleObject->ListEntry);
-  ModuleObject->Name = wcsdup(L"ntoskrnl.exe");
   DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
   ModuleObject->Image.PE.FileHeader =
     (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
@@ -186,9 +250,313 @@ static VOID LdrLoadAutoConfigDriver (LPWSTR       RelativeDriverName)
      }
 }
 
+#ifdef KDBG
+
+BOOLEAN LdrReadLine(PCHAR Line,
+                    PVOID *Buffer,
+                    PULONG Size)
+{
+  CHAR ch;
+  PCHAR Block;
+
+  if (*Size == 0)
+    return FALSE;
+
+  Block = *Buffer;
+  while ((*Size > 0) && ((ch = *Block) != (CHAR)13))
+    {
+      *Line = ch;
+      Line++;
+      Block++;
+      *Size -= 1;
+    }
+  *Line = (CHAR)0;
+
+  Block++;
+  *Size -= 1;
+
+  if ((*Size > 0) && (*Block == (CHAR)10))
+    {
+      Block++;
+      *Size -= 1;
+    }
+
+  *Buffer = Block;
+
+  return TRUE;
+}
+
+ULONG HexL(PCHAR Buffer)
+{
+  CHAR ch;
+  UINT i, j;
+  ULONG Value;
+
+  j     = 32;
+  i     = 0;
+  Value = 0;
+  while ((j > 0) && ((ch = Buffer[i]) != ' '))
+    {
+      j -= 4;
+      if ((ch >= '0') && (ch <= '9'))
+        Value |= ((ch - '0') << j);
+        if ((ch >= 'A') && (ch <= 'F'))
+          Value |= ((10 + (ch - 'A')) << j);
+        else
+          if ((ch >= 'a') && (ch <= 'f'))
+            Value |= ((10 + (ch - 'a')) << j);
+      i++;
+    }
+  return Value;
+}
+
+PSYMBOL LdrParseLine(PCHAR Line,
+                     PULONG ImageBase,
+                     PBOOLEAN ImageBaseValid)
+/*
+    Line format: [ADDRESS] <TYPE> <NAME>
+    TYPE:
+      U = ?
+      A = Image information
+      t = Symbol in text segment
+      T = Symbol in text segment
+      d = Symbol in data segment
+      D = Symbol in data segment
+      b = Symbol in BSS segment
+      B = Symbol in BSS segment
+      ? = Unknown segment or symbol in unknown segment
+*/
+{
+  ANSI_STRING AnsiString;
+  CHAR Buffer[128];
+  PSYMBOL Symbol;
+  ULONG Address;
+  PCHAR Str;
+  CHAR Type;
+
+  *ImageBaseValid = FALSE;
+
+  if ((Line[0] == (CHAR)0) || (Line[0] == ' '))
+    return NULL;
+
+  Address = HexL(Line);
+
+  Line = strchr(Line, ' ');
+  if (Line == NULL)
+    return NULL;
+
+  Line++;
+  Type = *Line;
+
+  Line = strchr(Line, ' ');
+  if (Line == NULL)
+    return NULL;
+
+  Line++;
+  Str = strchr(Line, ' ');
+  if (Str == NULL)
+    strcpy((char*)&Buffer, Line);
+  else
+    strncpy((char*)&Buffer, Line, Str - Line);
+
+  if ((Type == 'A') && (strcmp((char*)&Buffer, "__image_base__")) == 0)
+    {
+      *ImageBase      = Address;
+      *ImageBaseValid = TRUE;
+      return NULL;
+    }
+
+  /* We only want symbols in the .text segment */
+  if ((Type != 't') && (Type != 'T'))
+    return NULL;
+
+  /* Discard other symbols we can't use */
+  if ((Buffer[0] != '_') || ((Buffer[0] == '_') && (Buffer[1] == '_')))
+    return NULL;
+
+  Symbol = ExAllocatePool(NonPagedPool, sizeof(SYMBOL));
+  if (!Symbol)
+    return NULL;
+
+  Symbol->Next = NULL;
+
+  Symbol->RelativeAddress = Address;
+
+  RtlInitAnsiString(&AnsiString, (PCSZ)&Buffer);
+  RtlAnsiStringToUnicodeString(&Symbol->Name, &AnsiString, TRUE);
+
+  return Symbol;
+}
+
+VOID LdrLoadModuleSymbols(PMODULE_OBJECT ModuleObject,
+                         MODULE_TEXT_SECTION* ModuleTextSection)
+/*
+   Symbols must be sorted by address, e.g.
+   "nm --numeric-sort module.sys > module.sym"
+ */
+{
+  WCHAR TmpFileName[MAX_PATH];
+  LPWSTR Start, Ext;
+  ULONG Length, Tmp;
+  UNICODE_STRING Filename;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  NTSTATUS Status;
+  HANDLE FileHandle;
+  PVOID FileBuffer, FilePtr;
+  CHAR Line[256];
+  FILE_STANDARD_INFORMATION FileStdInfo;
+  BOOLEAN ImageBaseValid;
+  ULONG ImageBase = 0;
+  PSYMBOL Symbol, CurrentSymbol = NULL;
+
+  /*  Get the path to the symbol store  */
+  wcscpy(TmpFileName, L"\\SystemRoot\\symbols\\");
+
+  /*  Get the symbol filename from the module name  */
+  Start = wcsrchr(ModuleObject->BaseName.Buffer, L'\\');
+  if (Start == NULL)
+    Start = ModuleObject->BaseName.Buffer;
+  else
+    Start++;
+
+  Ext = wcsrchr(ModuleObject->BaseName.Buffer, L'.');
+  if (Ext != NULL)
+    Length = Ext - Start;
+  else
+    Length = wcslen(Start);
+
+  wcsncat(TmpFileName, Start, Length);
+  wcscat(TmpFileName, L".sym");
+  RtlInitUnicodeString(&Filename, TmpFileName);
+
+  /*  Open the file  */
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &Filename,
+                             0,
+                             NULL,
+                             NULL);
+
+  Status = ZwOpenFile(&FileHandle,
+                      FILE_ALL_ACCESS,
+                      &ObjectAttributes,
+                      NULL, 0, 0);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("Could not open symbol file: %wZ\n", &Filename);
+      return;
+    }
+
+  DbgPrint("Loading symbols from %wZ...\n", &Filename);
+
+  /*  Get the size of the file  */
+  Status = ZwQueryInformationFile(FileHandle,
+                                  NULL,
+                                  &FileStdInfo,
+                                  sizeof(FileStdInfo),
+                                  FileStandardInformation);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("Could not get file size\n");
+      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");
+      return;
+    }
+   
+  /*  Load file into memory chunk  */
+  Status = ZwReadFile(FileHandle, 
+                      0, 0, 0, 0, 
+                      FileBuffer, 
+                      FileStdInfo.EndOfFile.u.LowPart, 
+                      0, 0);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("Could not read symbol file into memory\n");
+      ExFreePool(FileBuffer);
+      return;
+    }
+
+  ZwClose(FileHandle);
+
+  ModuleTextSection->Symbols.SymbolCount = 0;
+  ModuleTextSection->Symbols.Symbols     = NULL;
+
+  FilePtr = FileBuffer;
+  Length  = FileStdInfo.EndOfFile.u.LowPart;
+
+  while (LdrReadLine((PCHAR)&Line, &FilePtr, &Length))
+    {
+      Symbol = LdrParseLine((PCHAR)&Line, &Tmp, &ImageBaseValid);
+
+      if (ImageBaseValid)
+        ImageBase = Tmp;
+
+      if (Symbol != NULL)
+        {
+          Symbol->RelativeAddress -= ImageBase;
+
+          if (ModuleTextSection->Symbols.Symbols == NULL)
+            ModuleTextSection->Symbols.Symbols = Symbol;
+          else
+            CurrentSymbol->Next = Symbol;
+
+          CurrentSymbol = Symbol;
+
+          ModuleTextSection->Symbols.SymbolCount++;
+        }
+    }
+
+  ExFreePool(FileBuffer);
+}
+
+#endif /* KDBG */
 
 VOID LdrLoadAutoConfigDrivers (VOID)
 {
+
+#ifdef KDBG
+
+  NTSTATUS Status;
+  WCHAR NameBuffer[60];
+  UNICODE_STRING ModuleName;
+  PMODULE_OBJECT ModuleObject;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING RemainingPath;
+
+  /* Load symbols for ntoskrnl.exe and hal.dll because \SystemRoot
+     is created after their module entries */
+
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  wcscat(NameBuffer, L"ntoskrnl.exe");
+  RtlInitUnicodeString(&ModuleName, NameBuffer);
+
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName,
+                             0,
+                             NULL,
+                             NULL);
+  
+  Status = ObFindObject(&ObjectAttributes,
+                        (PVOID*)&ModuleObject,
+                        &RemainingPath,
+                        NULL);
+  if (NT_SUCCESS(Status)) {
+    RtlFreeUnicodeString(&RemainingPath);
+
+    LdrLoadModuleSymbols(ModuleObject, &NtoskrnlTextSection);
+  }
+
+  /* FIXME: Load symbols for hal.dll */
+
+#endif /* KDBG */
+
    /*
     * Keyboard driver
     */
@@ -213,6 +581,36 @@ VOID LdrLoadAutoConfigDrivers (VOID)
     * Minix filesystem driver
     */
    LdrLoadAutoConfigDriver(L"minixfs.sys");
+
+   /*
+    * Networking
+    */
+#if 0
+   /*
+    * NDIS library
+    */
+   LdrLoadAutoConfigDriver(L"ndis.sys");
+
+   /*
+    * Novell Eagle 2000 driver
+    */
+   LdrLoadAutoConfigDriver(L"ne2000.sys");
+
+   /*
+    * TCP/IP protocol driver
+    */
+   LdrLoadAutoConfigDriver(L"tcpip.sys");
+
+   /*
+    * TDI test driver
+    */
+   LdrLoadAutoConfigDriver(L"tditest.sys");
+
+   /*
+    * Ancillary Function Driver
+    */
+   LdrLoadAutoConfigDriver(L"afd.sys");
+#endif
 }
 
 
@@ -299,9 +697,6 @@ LdrLoadModule(PUNICODE_STRING Filename)
   OBJECT_ATTRIBUTES ObjectAttributes;
   PMODULE_OBJECT  ModuleObject;
   FILE_STANDARD_INFORMATION FileStdInfo;
-  WCHAR  NameBuffer[60];
-//  PWSTR  RemainingPath;
-  UNICODE_STRING  ModuleName;
 
   /*  Check for module already loaded  */
   if ((ModuleObject = LdrOpenModule(Filename)) != NULL)
@@ -344,8 +739,9 @@ LdrLoadModule(PUNICODE_STRING Filename)
   CHECKPOINT;
 
   /*  Allocate nonpageable memory for driver  */
-  ModuleLoadBase = ExAllocatePool(NonPagedPool,
-                                  FileStdInfo.EndOfFile.u.LowPart);
+  ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
+                                        FileStdInfo.EndOfFile.u.LowPart,
+                                        TAG_DRIVER_MEM);
 
   if (ModuleLoadBase == NULL)
     {
@@ -371,19 +767,7 @@ LdrLoadModule(PUNICODE_STRING Filename)
 
   NtClose(FileHandle);
 
-  /*  Build module object name  */
-  wcscpy(NameBuffer, MODULE_ROOT_NAME);
-  if (wcsrchr(Filename->Buffer, '\\') != 0)
-    {
-      wcscat(NameBuffer, wcsrchr(Filename->Buffer, '\\') + 1);
-    }
-  else
-    {
-      wcscat(NameBuffer, Filename->Buffer);
-    }
-  RtlInitUnicodeString (&ModuleName, NameBuffer);
-
-  ModuleObject = LdrProcessModule(ModuleLoadBase, &ModuleName);
+  ModuleObject = LdrProcessModule(ModuleLoadBase, Filename);
 
   /*  Cleanup  */
   ExFreePool(ModuleLoadBase);
@@ -392,19 +776,25 @@ LdrLoadModule(PUNICODE_STRING Filename)
 }
 
 NTSTATUS
-LdrProcessDriver(PVOID ModuleLoadBase)
+LdrProcessDriver(PVOID ModuleLoadBase, PCHAR FileName)
 {
-  PMODULE_OBJECT ModuleObject;
-
-  ModuleObject = LdrProcessModule(ModuleLoadBase, 0);
-  if (ModuleObject == 0)
-    {
-      return STATUS_UNSUCCESSFUL;
-    }
+   PMODULE_OBJECT ModuleObject;
+   UNICODE_STRING ModuleName;
+
+   RtlCreateUnicodeStringFromAsciiz(&ModuleName,
+                                   FileName);
+   ModuleObject = LdrProcessModule(ModuleLoadBase,
+                                  &ModuleName);
+   RtlFreeUnicodeString(&ModuleName);
+   if (ModuleObject == NULL)
+     {
+       DPRINT1("Driver load was unsuccessful\n");
+       return(STATUS_UNSUCCESSFUL);
+     }
 
-  /* FIXME: should we dereference the ModuleObject here?  */
+   /* FIXME: should we dereference the ModuleObject here?  */
 
-  return IoInitializeDriver(ModuleObject->EntryPoint); 
+   return(IoInitializeDriver(ModuleObject->EntryPoint));
 }
 
 PMODULE_OBJECT
@@ -419,6 +809,7 @@ LdrProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING ModuleName)
       return LdrPEProcessModule(ModuleLoadBase, ModuleName);
     }
 
+  DPRINT1("Module wasn't PE\n");
   return 0;
 }
 
@@ -431,7 +822,6 @@ LdrOpenModule(PUNICODE_STRING  Filename)
   OBJECT_ATTRIBUTES  ObjectAttributes;
   PMODULE_OBJECT  ModuleObject;
   UNICODE_STRING RemainingPath;
-//  PWSTR  RemainingPath;
 
   wcscpy(NameBuffer, MODULE_ROOT_NAME);
   if (wcsrchr(Filename->Buffer, '\\') != 0)
@@ -482,10 +872,127 @@ LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
     }
 }
 
+NTSTATUS
+LdrpQueryModuleInformation(PVOID Buffer,
+                          ULONG Size,
+                          PULONG ReqSize)
+{
+   PLIST_ENTRY current_entry;
+   PMODULE_OBJECT current;
+   ULONG ModuleCount = 0;
+   PSYSTEM_MODULE_INFORMATION Smi;
+   ANSI_STRING AnsiName;
+   PCHAR p;
+
+//   KeAcquireSpinLock(&ModuleListLock,&oldlvl);
+
+   /* calculate required size */
+   current_entry = ModuleListHead.Flink;
+   while (current_entry != (&ModuleListHead))
+     {
+       ModuleCount++;
+       current_entry = current_entry->Flink;
+     }
+
+   *ReqSize = sizeof(SYSTEM_MODULE_INFORMATION)+
+       (ModuleCount - 1) * sizeof(SYSTEM_MODULE_ENTRY);
+
+   if (Size < *ReqSize)
+     {
+//     KeReleaseSpinLock(&ModuleListLock,oldlvl);
+       return STATUS_INFO_LENGTH_MISMATCH;
+     }
+
+   /* fill the buffer */
+   memset(Buffer, '=', Size);
+
+   Smi = (PSYSTEM_MODULE_INFORMATION)Buffer;
+   Smi->Count = ModuleCount;
+
+   ModuleCount = 0;
+   current_entry = ModuleListHead.Flink;
+   while (current_entry != (&ModuleListHead))
+     {
+       current = CONTAINING_RECORD(current_entry,MODULE_OBJECT,ListEntry);
+
+       Smi->Module[ModuleCount].Unknown2 = 0;          /* Always 0 */
+       Smi->Module[ModuleCount].BaseAddress = current->Base;
+       Smi->Module[ModuleCount].Size = current->Length;
+       Smi->Module[ModuleCount].Flags = 0;             /* Flags ??? (GN) */
+       Smi->Module[ModuleCount].EntryIndex = ModuleCount;
+
+       AnsiName.Length = 0;
+       AnsiName.MaximumLength = 256;
+       AnsiName.Buffer = Smi->Module[ModuleCount].Name;
+       RtlUnicodeStringToAnsiString(&AnsiName,
+                                    &current->FullName,
+                                    FALSE);
+
+       p = strrchr (AnsiName.Buffer, '\\');
+       if (p == NULL)
+         {
+            Smi->Module[ModuleCount].PathLength = 0;
+            Smi->Module[ModuleCount].NameLength = strlen(AnsiName.Buffer);
+         }
+       else
+         {
+            p++;
+            Smi->Module[ModuleCount].PathLength = p - AnsiName.Buffer;
+            Smi->Module[ModuleCount].NameLength = strlen(p);
+         }
+
+       ModuleCount++;
+       current_entry = current_entry->Flink;
+     }
+
+//   KeReleaseSpinLock(&ModuleListLock,oldlvl);
+
+   return STATUS_SUCCESS;
+}
+
+
+static VOID
+LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
+                       PUNICODE_STRING FullName)
+{
+   UNICODE_STRING Name;
+   PWCHAR p;
+   PWCHAR q;
+
+   DPRINT("LdrpBuildModuleBaseName()\n");
+   DPRINT("FullName %wZ\n", FullName);
+
+   p = wcsrchr(FullName->Buffer, '\\');
+   if (p == NULL)
+     {
+       p = FullName->Buffer;
+     }
+   else
+     {
+       p++;
+     }
+
+   DPRINT("p %S\n", p);
+
+   RtlCreateUnicodeString(&Name, p);
+
+   q = wcschr(p, '.');
+   if (q != NULL)
+     {
+       *q = (WCHAR)0;
+     }
+
+   DPRINT("p %S\n", p);
+
+   RtlCreateUnicodeString(BaseName, p);
+   RtlFreeUnicodeString(&Name);
+}
+
+
 /*  ----------------------------------------------  PE Module support */
 
 PMODULE_OBJECT
-LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING pModuleName)
+LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING FileName)
 {
   unsigned int DriverSize, Idx, Idx2;
   ULONG RelocDelta, NumRelocs;
@@ -496,7 +1003,6 @@ LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING pModuleName)
   PIMAGE_FILE_HEADER PEFileHeader;
   PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
   PIMAGE_SECTION_HEADER PESectionHeaders;
-  PIMAGE_EXPORT_DIRECTORY  ExportDirectory;
   PRELOCATION_DIRECTORY RelocDir;
   PRELOCATION_ENTRY RelocEntry;
   PMODULE_OBJECT  LibraryModuleObject;
@@ -509,6 +1015,7 @@ LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING pModuleName)
   OBJECT_ATTRIBUTES  ObjectAttributes;
   UNICODE_STRING  ModuleName;
   WCHAR  NameBuffer[60];
+  MODULE_TEXT_SECTION* ModuleTextSection;
 
   DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
 
@@ -685,7 +1192,7 @@ LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING pModuleName)
     {
       PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
 
-      SymbolNameBuf = ExAllocatePool(NonPagedPool, 512);
+      SymbolNameBuf = ExAllocatePoolWithTag(NonPagedPool, 512, TAG_SYM_BUF);
 
       /*  Process each import module  */
       ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
@@ -768,32 +1275,14 @@ LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING pModuleName)
     }
 
   /*  Create ModuleName string  */
-  if (pModuleName != 0)
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  if (wcsrchr(FileName->Buffer, '\\') != 0)
     {
-      wcscpy(NameBuffer, pModuleName->Buffer);
+      wcscat(NameBuffer, wcsrchr(FileName->Buffer, '\\') + 1);
     }
   else
     {
-      wcscpy(NameBuffer, MODULE_ROOT_NAME);
-      if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
-            .VirtualAddress != 0)
-        {
-          ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) (DriverBase +
-            PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
-              .VirtualAddress);
-          wcscat(NameBuffer, DriverBase + ExportDirectory->Name);
-        }
-      else
-        {
-          char buf[12];
-
-          sprintf(buf, "%08X", (DWORD) DriverBase);
-          for (Idx = 0; NameBuffer[Idx] != 0; Idx++)
-            ;
-          Idx2 = 0;
-          while ((NameBuffer[Idx + Idx2] = (WCHAR) buf[Idx2]) != 0)
-            Idx2++;
-        }
+      wcscat(NameBuffer, FileName->Buffer);
     }
   RtlInitUnicodeString (&ModuleName, NameBuffer);
   DbgPrint("Module name is: %wZ\n", &ModuleName);
@@ -812,11 +1301,16 @@ LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING pModuleName)
                                 &ObjectAttributes,
                                 IoDriverObjectType);
 
-  /*  Initialize ModuleObject data  */
-  ModuleObject->Base = DriverBase;
-  ModuleObject->Flags = MODULE_FLAG_PE;
-  InsertTailList(&ModuleListHead, &ModuleObject->ListEntry);
-  ModuleObject->Name = wcsdup(NameBuffer);
+   /*  Initialize ModuleObject data  */
+   ModuleObject->Base = DriverBase;
+   ModuleObject->Flags = MODULE_FLAG_PE;
+   InsertTailList(&ModuleListHead,
+                 &ModuleObject->ListEntry);
+   RtlCreateUnicodeString(&ModuleObject->FullName,
+                         FileName->Buffer);
+   LdrpBuildModuleBaseName(&ModuleObject->BaseName,
+                          &ModuleObject->FullName);
+
   ModuleObject->EntryPoint = (PVOID) ((DWORD)DriverBase + 
     PEOptionalHeader->AddressOfEntryPoint);
   ModuleObject->Length = DriverSize;
@@ -835,50 +1329,61 @@ LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING pModuleName)
     sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER));
   DPRINT("SectionList at %x\n", ModuleObject->Image.PE.SectionList);
 
+  ModuleTextSection = ExAllocatePool(NonPagedPool, 
+                                    sizeof(MODULE_TEXT_SECTION));
+  ModuleTextSection->Base = (ULONG)DriverBase;
+  ModuleTextSection->Length = DriverSize;
+  ModuleTextSection->SymbolsBase = NULL;
+  ModuleTextSection->SymbolsLength = 0;
+  ModuleTextSection->Name = 
+    ExAllocatePool(NonPagedPool, 
+                  (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
+  wcscpy(ModuleTextSection->Name, NameBuffer);
+  InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
+
+#ifdef KDBG
+
+       /* Load symbols for module if available */
+  LdrLoadModuleSymbols(ModuleObject, ModuleTextSection);
+
+#endif /* KDBG */
+
   return  ModuleObject;
 }
 
-static PVOID  
+static PVOID
 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
                       char *Name,
                       unsigned short Hint)
 {
   WORD  Idx;
-  DWORD  ExportsStartRVA, ExportsEndRVA;
   PVOID  ExportAddress;
   PWORD  OrdinalList;
   PDWORD  FunctionList, NameList;
-  PIMAGE_SECTION_HEADER  SectionHeader;
-  PIMAGE_EXPORT_DIRECTORY  ExportDirectory;
-
-  ExportsStartRVA = ModuleObject->Image.PE.OptionalHeader->DataDirectory
-    [IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
-  ExportsEndRVA = ExportsStartRVA + 
-    ModuleObject->Image.PE.OptionalHeader->DataDirectory
-      [IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
-
-  /*  Get the IMAGE_SECTION_HEADER that contains the exports.  This is
-      usually the .edata section, but doesn't have to be.  */
-  SectionHeader = LdrPEGetEnclosingSectionHeader(ExportsStartRVA, ModuleObject);
-
-  if (!SectionHeader)
-    {
-      return 0;
-    }
+   PIMAGE_EXPORT_DIRECTORY  ExportDir;
+   ULONG ExportDirSize;
+
+   ExportDir = (PIMAGE_EXPORT_DIRECTORY)
+     RtlImageDirectoryEntryToData(ModuleObject->Base,
+                                 TRUE,
+                                 IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                 &ExportDirSize);
+   DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
+   if (ExportDir == NULL)
+     {
+       return NULL;
+     }
 
-  ExportDirectory = MakePtr(PIMAGE_EXPORT_DIRECTORY,
-                            ModuleObject->Base,
-                            SectionHeader->VirtualAddress);
 
-  FunctionList = (PDWORD)((DWORD)ExportDirectory->AddressOfFunctions + ModuleObject->Base);
-  NameList = (PDWORD)((DWORD)ExportDirectory->AddressOfNames + ModuleObject->Base);
-  OrdinalList = (PWORD)((DWORD)ExportDirectory->AddressOfNameOrdinals + ModuleObject->Base);
+   FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ModuleObject->Base);
+   NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ModuleObject->Base);
+   OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ModuleObject->Base);
 
   ExportAddress = 0;
 
   if (Name != NULL)
     {
-      for (Idx = 0; Idx < ExportDirectory->NumberOfNames; Idx++)
+      for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
         {
 #if 0
           DPRINT("  Name:%s  NameList[%d]:%s\n", 
@@ -891,6 +1396,14 @@ LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
             {
               ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
                 FunctionList[OrdinalList[Idx]]);
+                 if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
+                     ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
+                   {
+                      DPRINT("Forward: %s\n", (PCHAR)ExportAddress);
+                      ExportAddress = LdrPEFixupForward((PCHAR)ExportAddress);
+                      DPRINT("ExportAddress: %p\n", ExportAddress);
+                   }
+
               break;
             }
         }
@@ -898,37 +1411,91 @@ LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
   else  /*  use hint  */
     {
       ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
-        FunctionList[Hint - ExportDirectory->Base]);
-    }
-  if (ExportAddress == 0)
-    {
-       DbgPrint("Export not found for %d:%s\n", Hint, 
-               Name != NULL ? Name : "(Ordinal)");
-       KeBugCheck(0);
+        FunctionList[Hint - ExportDir->Base]);
     }
 
-  return  ExportAddress;
+   if (ExportAddress == 0)
+     {
+       DbgPrint("Export not found for %d:%s\n",
+                Hint,
+                Name != NULL ? Name : "(Ordinal)");
+       KeBugCheck(0);
+     }
+
+   return ExportAddress;
 }
 
-static PIMAGE_SECTION_HEADER 
-LdrPEGetEnclosingSectionHeader(DWORD  RVA,
-                               PMODULE_OBJECT  ModuleObject)
+
+static PMODULE_OBJECT
+LdrPEGetModuleObject(PUNICODE_STRING ModuleName)
 {
-  PIMAGE_SECTION_HEADER  SectionHeader = SECHDROFFSET(ModuleObject->Base);
-  unsigned  i;
+   PLIST_ENTRY Entry;
+   PMODULE_OBJECT Module;
 
-  for (i = 0; i < ModuleObject->Image.PE.FileHeader->NumberOfSections; 
-       i++, SectionHeader++)
-    {
-      /*  Is the RVA within this section?  */
-      if ((RVA >= SectionHeader->VirtualAddress) && 
-          (RVA < (SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize)))
-        {
-          return SectionHeader;
-        }
-    }
+   DPRINT("LdrPEGetModuleObject (ModuleName %wZ)\n",
+          ModuleName);
 
-  return 0;
+   Entry = ModuleListHead.Flink;
+
+   while (Entry != &ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, MODULE_OBJECT, ListEntry);
+
+       DPRINT("Comparing %wZ and %wZ\n",
+              &Module->BaseName,
+              ModuleName);
+
+       if (!RtlCompareUnicodeString(&Module->BaseName, ModuleName, TRUE))
+         {
+            DPRINT("Module %x\n", Module);
+            return Module;
+         }
+
+       Entry = Entry->Flink;
+     }
+
+   DbgPrint("LdrPEGetModuleObject: Failed to find dll %wZ\n", ModuleName);
+
+   return NULL;
+}
+
+
+static PVOID
+LdrPEFixupForward(PCHAR ForwardName)
+{
+   CHAR NameBuffer[128];
+   UNICODE_STRING ModuleName;
+   PCHAR p;
+   PMODULE_OBJECT ModuleObject;
+
+   DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
+
+   strcpy(NameBuffer, ForwardName);
+   p = strchr(NameBuffer, '.');
+   if (p == NULL)
+     {
+       return NULL;
+     }
+
+   *p = 0;
+
+   DPRINT("Driver: %s  Function: %s\n", NameBuffer, p+1);
+
+   RtlCreateUnicodeStringFromAsciiz(&ModuleName,
+                                   NameBuffer);
+   ModuleObject = LdrPEGetModuleObject(&ModuleName);
+   RtlFreeUnicodeString(&ModuleName);
+
+   DPRINT("ModuleObject: %p\n", ModuleObject);
+
+   if (ModuleObject == NULL)
+     {
+       DbgPrint("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
+       return NULL;
+     }
+
+   return LdrPEGetExportAddress(ModuleObject, p+1, 0);
 }
 
+
 /* EOF */