Compilation bug fixed (due to having used an "unknown" field in the
[reactos.git] / reactos / ntoskrnl / ldr / loader.c
index 215d2fe..085f831 100644 (file)
-/*
+/* $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
  * FILE:            ntoskrnl/ldr/loader.c
  * PURPOSE:         Loaders for PE executables
- * PROGRAMMER:      Rex Jolliff (rex@lvcablemodem.com)
+ * 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 loader function and added hooks for MZ/PE 
+ *   DW   22/05/98   Created
+ *   RJJ  10/12/98   Completed image loader function and added hooks for MZ/PE
+ *   RJJ  10/12/98   Built driver loader function and added hooks for PE/COFF
+ *   RJJ  10/12/98   Rolled in David's code to load COFF drivers
+ *   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/2000 Removed redundant header files
+ *   CSH  11/04/2001 Added automatic loading of module symbols if they exist
  */
 
+
 /* INCLUDES *****************************************************************/
 
-#include <internal/i386/segment.h>
-#include <internal/kernel.h>
-#include <internal/linkage.h>
+#include <limits.h>
+#include <ddk/ntddk.h>
+#include <internal/config.h>
 #include <internal/module.h>
-#include <internal/string.h>
-#include <internal/symbol.h>
+#include <internal/ntoskrnl.h>
+#include <internal/mm.h>
+#include <internal/ob.h>
+#include <internal/ps.h>
+#include <internal/ldr.h>
+#include <internal/pool.h>
+
+#define NDEBUG
+#include <internal/debug.h>
 
-#include <ddk/ntddk.h>
-#include <ddk/li.h>
 
-//#define NDEBUG
-#include <internal/debug.h>
+/* FIXME: this should appear in a kernel header file  */
+NTSTATUS IoInitializeDriver(PDRIVER_INITIALIZE DriverEntry);
 
-#include "pe.h"
+/* MACROS ********************************************************************/
 
-/* FUNCTIONS *****************************************************************/
+#define  MODULE_ROOT_NAME  L"\\Modules\\"
 
-/* COFF Driver load support **************************************************/
-static BOOLEAN LdrCOFFDoRelocations(module *Module, unsigned int SectionIndex);
-static BOOLEAN LdrCOFFDoAddr32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation);
-static BOOLEAN LdrCOFFDoReloc32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation);
-static void LdrCOFFGetSymbolName(module *Module, unsigned int Idx, char *Name);
-static unsigned int LdrCOFFGetSymbolValue(module *Module, unsigned int Idx);
-static unsigned int LdrCOFFGetKernelSymbolAddr(char *Name);
-static unsigned int LdrCOFFGetSymbolValueByName(module *Module, char *SymbolName, unsigned int Idx);
+/* GLOBALS *******************************************************************/
 
-static NTSTATUS 
-LdrCOFFProcessDriver(HANDLE FileHandle)
+LIST_ENTRY ModuleListHead;
+POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
+LIST_ENTRY ModuleTextListHead;
+STATIC MODULE_TEXT_SECTION NtoskrnlTextSection;
+/* STATIC MODULE_TEXT_SECTION HalTextSection; */
+
+#define TAG_DRIVER_MEM  TAG('D', 'R', 'V', 'M')
+#define TAG_SYM_BUF     TAG('S', 'Y', 'M', 'B')
+
+/* FORWARD DECLARATIONS ******************************************************/
+
+PMODULE_OBJECT  LdrLoadModule(PUNICODE_STRING Filename);
+PMODULE_OBJECT  LdrProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING ModuleName);
+PVOID  LdrGetExportAddress(PMODULE_OBJECT ModuleObject, char *Name, unsigned short Hint);
+static PMODULE_OBJECT LdrOpenModule(PUNICODE_STRING  Filename);
+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 FileName);
+static PVOID  LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
+                                    char *Name,
+                                    unsigned short Hint);
+static PMODULE_OBJECT LdrPEGetModuleObject(PUNICODE_STRING ModuleName);
+static PVOID LdrPEFixupForward(PCHAR ForwardName);
+
+
+/* FUNCTIONS *****************************************************************/
+
+VOID
+LdrInitDebug(PLOADER_MODULE Module, PWCH Name)
 {
-  BOOLEAN FoundEntry;
-  char SymbolName[255];
-  int i;
-  NTSTATUS Status;
-  PVOID ModuleLoadBase;
-  ULONG EntryOffset;
-  FILHDR *FileHeader;
-  AOUTHDR *AOUTHeader;
-  module *Module;
-  FILE_STANDARD_INFORMATION FileStdInfo;
-  PDRIVER_INITIALIZE EntryRoutine;
+  PLIST_ENTRY current_entry;
+  MODULE_TEXT_SECTION* current;
 
-  /*  Get the size of the file for the section  */
-  Status = ZwQueryInformationFile(FileHandle,
-                                  NULL,
-                                  &FileStdInfo,
-                                  sizeof(FileStdInfo),
-                                  FileStandardInformation);
-  if (!NT_SUCCESS(Status))
+  current_entry = ModuleTextListHead.Flink;
+  while (current_entry != &ModuleTextListHead)
     {
-      return Status;
+      current = 
+       CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
+      if (wcscmp(current->Name, Name) == 0)
+       {
+         break;
+       }
+      current_entry = current_entry->Flink;
     }
-  CHECKPOINT;
 
-  /*  Allocate nonpageable memory for driver  */
-  ModuleLoadBase = ExAllocatePool(NonPagedPool, 
-                 GET_LARGE_INTEGER_LOW_PART(FileStdInfo.AllocationSize));
-  if (ModuleLoadBase == NULL)
+  if (current_entry == &ModuleTextListHead)
     {
-      return STATUS_INSUFFICIENT_RESOURCES;
+      return;
     }
-  CHECKPOINT;
+  
+  current->SymbolsBase = (PVOID)Module->ModStart;
+  current->SymbolsLength = Module->ModEnd - Module->ModStart;
+}
 
-  /*  Load driver into memory chunk  */
-  Status = ZwReadFile(FileHandle, 
-                      0, 0, 0, 0, 
-                      ModuleLoadBase, 
-                      GET_LARGE_INTEGER_LOW_PART(FileStdInfo.AllocationSize), 
-                      0, 0);
-  if (!NT_SUCCESS(Status))
+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];
+  UNICODE_STRING ModuleName;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  PIMAGE_DOS_HEADER DosHeader;
+  PMODULE_OBJECT ModuleObject;
+
+  /*  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;
+  IoDriverObjectType->MaxHandles = ULONG_MAX;
+  IoDriverObjectType->PagedPoolCharge = 0;
+  IoDriverObjectType->NonpagedPoolCharge = sizeof(MODULE);
+  IoDriverObjectType->Dump = NULL;
+  IoDriverObjectType->Open = NULL;
+  IoDriverObjectType->Close = NULL;
+  IoDriverObjectType->Delete = NULL;
+  IoDriverObjectType->Parse = NULL;
+  IoDriverObjectType->Security = NULL;
+  IoDriverObjectType->QueryName = NULL;
+  IoDriverObjectType->OkayToClose = NULL;
+  IoDriverObjectType->Create = LdrCreateModule;
+  RtlInitUnicodeString(&IoDriverObjectType->TypeName, L"Driver");
+
+  /*  Create Modules object directory  */
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  *(wcsrchr(NameBuffer, L'\\')) = 0;
+  RtlInitUnicodeString (&ModuleName, NameBuffer);
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName,
+                             0,
+                             NULL,
+                             NULL);
+  DPRINT("Create dir: %wZ\n", &ModuleName);
+  Status = NtCreateDirectoryObject(&DirHandle, 0, &ObjectAttributes);
+  assert(NT_SUCCESS(Status));
+
+  /*  Add module entry for NTOSKRNL  */
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  wcscat(NameBuffer, L"ntoskrnl.exe");
+  RtlInitUnicodeString (&ModuleName, NameBuffer);
+  DPRINT("Kernel's Module name is: %wZ\n", &ModuleName);
+
+  /*  Initialize ObjectAttributes for ModuleObject  */
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName,
+                             0,
+                             NULL,
+                             NULL);
+
+  /*  Create module object  */
+  ModuleHandle = 0;
+  ModuleObject = ObCreateObject(&ModuleHandle,
+                                STANDARD_RIGHTS_REQUIRED,
+                                &ObjectAttributes,
+                                IoDriverObjectType);
+  assert(ModuleObject != NULL);
+
+   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);
+
+  DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
+  ModuleObject->Image.PE.FileHeader =
+    (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
+    DosHeader->e_lfanew + sizeof(ULONG));
+  ModuleObject->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
+    ((DWORD)ModuleObject->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
+  ModuleObject->Image.PE.SectionList = (PIMAGE_SECTION_HEADER)
+    ((DWORD)ModuleObject->Image.PE.OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
+  ModuleObject->EntryPoint = (PVOID) ((DWORD) ModuleObject->Base +
+    ModuleObject->Image.PE.OptionalHeader->AddressOfEntryPoint);
+  DPRINT("ModuleObject:%08x  entrypoint at %x\n", ModuleObject, ModuleObject->EntryPoint);
+   ModuleObject->Length = ModuleObject->Image.PE.OptionalHeader->SizeOfImage;
+
+  /* FIXME: Add fake module entry for HAL */
+
+}
+
+/*
+ * load the auto config drivers.
+ */
+static VOID LdrLoadAutoConfigDriver (LPWSTR    RelativeDriverName)
+{
+   WCHAR               TmpFileName [MAX_PATH];
+   NTSTATUS    Status;
+   UNICODE_STRING      DriverName;
+
+   DbgPrint("Loading %S\n",RelativeDriverName);
+
+   wcscpy(TmpFileName, L"\\SystemRoot\\system32\\drivers\\");
+   wcscat(TmpFileName, RelativeDriverName);
+   RtlInitUnicodeString (&DriverName, TmpFileName);
+
+   Status = LdrLoadDriver(&DriverName);
+   if (!NT_SUCCESS(Status))
+     {
+       DbgPrint("driver load failed, status (%x)\n", Status);
+//     KeBugCheck(0);
+     }
+}
+
+#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))
     {
-      ExFreePool(ModuleLoadBase);
-      return Status;
+      *Line = ch;
+      Line++;
+      Block++;
+      *Size -= 1;
     }
-  CHECKPOINT;
+  *Line = (CHAR)0;
 
-  /*  Get header pointers  */
-  FileHeader = ModuleLoadBase;
-  AOUTHeader = ModuleLoadBase + FILHSZ;
-  CHECKPOINT;
+  Block++;
+  *Size -= 1;
 
-  /*  Check COFF magic value  */
-  if (I386BADMAG(*FileHeader))
+  if ((*Size > 0) && (*Block == (CHAR)10))
     {
-      DbgPrint("Module has bad magic value (%x)\n", 
-               FileHeader->f_magic);
-      ExFreePool(ModuleLoadBase);
-      return STATUS_UNSUCCESSFUL;
+      Block++;
+      *Size -= 1;
     }
-  CHECKPOINT;
-   
-  /*  Allocate and initialize a module definition structure  */
-  Module = (module *) ExAllocatePool(NonPagedPool, sizeof(module));
-  if (Module == NULL)
-    {
-      ExFreePool(ModuleLoadBase);
-      return STATUS_INSUFFICIENT_RESOURCES;
-    }
-  Module->sym_list = (SYMENT *)(ModuleLoadBase + FileHeader->f_symptr);
-  Module->str_tab = (char *)(ModuleLoadBase + FileHeader->f_symptr +
-    FileHeader->f_nsyms * SYMESZ);
-  Module->scn_list = (SCNHDR *)(ModuleLoadBase + FILHSZ + 
-    FileHeader->f_opthdr);
-  Module->size = 0;
-  Module->raw_data_off = (ULONG) ModuleLoadBase;
-  Module->nsyms = FileHeader->f_nsyms;
-  CHECKPOINT;
 
-  /*  Determine the length of the module  */
-  for (i = 0; i < FileHeader->f_nscns; i++)
+  *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]) != ' '))
     {
-      DPRINT("Section name: %.8s\n", Module->scn_list[i].s_name);
-      DPRINT("size %x vaddr %x size %x\n",
-             Module->size,
-             Module->scn_list[i].s_vaddr,
-             Module->scn_list[i].s_size);
-      if (Module->scn_list[i].s_flags & STYP_TEXT)
-        {
-          Module->text_base = Module->scn_list[i].s_vaddr;
-        }
-      if (Module->scn_list[i].s_flags & STYP_DATA)
-        {
-          Module->data_base = Module->scn_list[i].s_vaddr;
-        }
-      if (Module->scn_list[i].s_flags & STYP_BSS)
-        {
-          Module->bss_base = Module->scn_list[i].s_vaddr;
-        }
-      if (Module->size <
-          (Module->scn_list[i].s_vaddr + Module->scn_list[i].s_size))
-        {
-          Module->size = Module->size + Module->scn_list[i].s_vaddr +
-            Module->scn_list[i].s_size;
-        }
+      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++;
     }
-  CHECKPOINT;
+  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;
 
-  /*  Allocate a section for the module  */
-  Module->base = (unsigned int) MmAllocateSection(Module->size);
-  if (Module->base == 0)
+  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)
     {
-      DbgPrint("Failed to alloc section for module\n");
-      ExFreePool(Module);
-      ExFreePool(ModuleLoadBase);
-      return STATUS_INSUFFICIENT_RESOURCES;
+      *ImageBase      = Address;
+      *ImageBaseValid = TRUE;
+      return NULL;
     }
-  CHECKPOINT;
 
-  /*  Adjust section vaddrs for allocated area  */
-  Module->data_base = Module->data_base + Module->base;
-  Module->text_base = Module->text_base + Module->base;
-  Module->bss_base = Module->bss_base + Module->base;
-   
-  /*  Relocate module and fixup imports  */
-  for (i = 0; i < FileHeader->f_nscns; i++)
+  /* 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))
     {
-      if (Module->scn_list[i].s_flags & STYP_TEXT ||
-          Module->scn_list[i].s_flags & STYP_DATA)
-        {
-          memcpy((PVOID)(Module->base + Module->scn_list[i].s_vaddr),
-                 (PVOID)(ModuleLoadBase + Module->scn_list[i].s_scnptr),
-                 Module->scn_list[i].s_size);
-          if (!LdrCOFFDoRelocations(Module, i))
-            {
-              DPRINT("Relocation failed for section %s\n",
-                     Module->scn_list[i].s_name);
-              ExFreePool(Module);
-              ExFreePool(ModuleLoadBase);
-              return STATUS_UNSUCCESSFUL;
-            }
-        }
-      if (Module->scn_list[i].s_flags & STYP_BSS)
-        {
-          memset((PVOID)(Module->base + Module->scn_list[i].s_vaddr),
-                 0,
-                 Module->scn_list[i].s_size);
-        }
+      DPRINT("Could not open symbol file: %wZ\n", &Filename);
+      return;
     }
-   
-  DbgPrint("Module base: %x\n", Module->base);
-   
-  /*  Find the entry point  */
-  EntryOffset = 0L;
-  FoundEntry = FALSE;
-  for (i = 0; i < FileHeader->f_nsyms; i++)
+
+  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))
     {
-      LdrCOFFGetSymbolName(Module, i, SymbolName);
-      if (!strcmp(SymbolName, "_DriverEntry"))
-        {
-          EntryOffset = Module->sym_list[i].e_value;
-          FoundEntry = TRUE;
-          DPRINT("Found entry at %x\n", EntryOffset);
-        }
+      DPRINT("Could not get file size\n");
+      return;
     }
-  if (!FoundEntry)
+
+  /*  Allocate nonpageable memory for symbol file  */
+  FileBuffer = ExAllocatePool(NonPagedPool,
+                              FileStdInfo.EndOfFile.u.LowPart);
+
+  if (FileBuffer == NULL)
     {
-      DbgPrint("No module entry point defined\n");
-      ExFreePool(Module);
-      ExFreePool(ModuleLoadBase);
-      return STATUS_UNSUCCESSFUL;
+      DPRINT("Could not allocate memory for symbol file\n");
+      return;
     }
    
-  /*  Call the module initalization routine  */
-  EntryRoutine = (PDRIVER_INITIALIZE)(Module->base + EntryOffset);
+  /*  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;
+    }
 
-  return InitalizeLoadedDriver(EntryRoutine);
-}
+  ZwClose(FileHandle);
 
-/*   LdrCOFFDoRelocations
- * FUNCTION: Do the relocations for a module section
- * ARGUMENTS:
- *          Module = Pointer to the module 
- *          SectionIndex = Index of the section to be relocated
- * RETURNS: Success or failure
- */
+  ModuleTextSection->Symbols.SymbolCount = 0;
+  ModuleTextSection->Symbols.Symbols     = NULL;
 
-static BOOLEAN 
-LdrCOFFDoRelocations(module *Module, unsigned int SectionIndex)
-{
-  SCNHDR *Section = &Module->scn_list[SectionIndex];
-  RELOC *Relocation = (RELOC *)(Module->raw_data_off + Section->s_relptr);
-  int j;
-   
-  DPRINT("SectionIndex %d Name %.8s Relocs %d\n",
-         SectionIndex,
-         Module->scn_list[SectionIndex].s_name,
-         Section->s_nreloc);
+  FilePtr = FileBuffer;
+  Length  = FileStdInfo.EndOfFile.u.LowPart;
 
-  for (j = 0; j < Section->s_nreloc; j++)
+  while (LdrReadLine((PCHAR)&Line, &FilePtr, &Length))
     {
-      DbgPrint("vaddr %x ", Relocation->r_vaddr);
-      DbgPrint("symndex %x ", Relocation->r_symndx);
+      Symbol = LdrParseLine((PCHAR)&Line, &Tmp, &ImageBaseValid);
+
+      if (ImageBaseValid)
+        ImageBase = Tmp;
 
-      switch (Relocation->r_type)
+      if (Symbol != NULL)
         {
-          case RELOC_ADDR32:
-            if (!LdrCOFFDoAddr32Reloc(Module, Section, Relocation))
-              {
-                return FALSE;
-              }
-            break;
-            
-          case RELOC_REL32:
-            if (!LdrCOFFDoReloc32Reloc(Module, Section, Relocation))
-              {
-                return FALSE;
-              }
-            break;
-
-          default:
-            DbgPrint("%.8s: Unknown relocation type %x at %d in module\n",
-                     Module->scn_list[SectionIndex].s_name,
-                    Relocation->r_type,
-                     j);
-            return FALSE;
+          Symbol->RelativeAddress -= ImageBase;
+
+          if (ModuleTextSection->Symbols.Symbols == NULL)
+            ModuleTextSection->Symbols.Symbols = Symbol;
+          else
+            CurrentSymbol->Next = Symbol;
+
+          CurrentSymbol = Symbol;
+
+          ModuleTextSection->Symbols.SymbolCount++;
         }
-      Relocation++;
     }
-   DPRINT("%.8s: relocations done\n", Module->scn_list[SectionIndex].s_name);
-   
-   return TRUE;
-}                   
 
-/*
- * FUNCTION: Performs a addr32 relocation on a loaded module
- * ARGUMENTS:
- *         mod = module to perform the relocation on
- *         scn = Section to perform the relocation in
- *         reloc = Pointer to a data structure describing the relocation
- * RETURNS: Success or failure
- * NOTE: This fixes up a relocation needed when changing the base address of a
- * module
- */
+  ExFreePool(FileBuffer);
+}
+
+#endif /* KDBG */
 
-static BOOLEAN
-LdrCOFFDoAddr32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation)
+VOID LdrLoadAutoConfigDrivers (VOID)
 {
-  unsigned int Value;
-  unsigned int *Location;
+
+#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
+    */
+   LdrLoadAutoConfigDriver( L"keyboard.sys" );
    
-  Value = LdrCOFFGetSymbolValue(Module, Relocation->r_symndx);
-  Location = (unsigned int *)(Module->base + Relocation->r_vaddr);
-  DbgPrint("ADDR32 loc %x value %x *loc %x ", Location, Value, *Location);
-  *Location = (*Location) + Module->base;
+   /*
+    * Raw console driver
+    */
+   LdrLoadAutoConfigDriver( L"blue.sys" );
    
-  return TRUE;
+   /*
+    * 
+    */
+   LdrLoadAutoConfigDriver(L"vidport.sys");
+   
+   /*
+    * 
+    */
+   LdrLoadAutoConfigDriver(L"vgamp.sys");
+   
+   /*
+    * 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
 }
 
-/*
- * FUNCTION: Performs a reloc32 relocation on a loaded module
- * ARGUMENTS:
- *         mod = module to perform the relocation on
- *         scn = Section to perform the relocation in
- *         reloc = Pointer to a data structure describing the relocation
- * RETURNS: Success or failure
- * NOTE: This fixes up an undefined reference to a kernel function in a module
- */
 
-static BOOLEAN
-LdrCOFFDoReloc32Reloc(module *Module, SCNHDR *Section, RELOC *Relocation)
+static NTSTATUS 
+LdrCreateModule(PVOID ObjectBody,
+                PVOID Parent,
+                PWSTR RemainingPath,
+                POBJECT_ATTRIBUTES ObjectAttributes)
 {
-  char Name[255];
-  unsigned int Value;
-  unsigned int *Location;
-   
-  memset(Name, 0, 255);
-  LdrCOFFGetSymbolName(Module, Relocation->r_symndx, Name);
-  Value = (unsigned int) LdrCOFFGetKernelSymbolAddr(Name);
-  if (Value == 0L)
+  DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
+         ObjectBody,
+         Parent,
+         RemainingPath);
+  if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
     {
-      Value = LdrCOFFGetSymbolValueByName(Module, Name, Relocation->r_symndx);
-      if (Value == 0L)
-        {
-          DbgPrint("Undefined symbol %s in module\n", Name);
-          return FALSE;
-        }
-      Location = (unsigned int *)(Module->base + Relocation->r_vaddr);
-//        (*Location) = (*Location) + Value + Module->base - Section->s_vaddr;
-      (*Location) = (*Location);
-      DPRINT("Module->base %x Section->s_vaddr %x\n", 
-             Module->base, 
-             Section->s_vaddr);
+      return  STATUS_UNSUCCESSFUL;
     }
-  else
+  if (Parent != NULL && RemainingPath != NULL)
     {
-      DPRINT("REL32 value %x name %s\n", Value, Name);
-      Location = (unsigned int *)(Module->base + Relocation->r_vaddr);
-      DPRINT("old %x ", *Location);
-      DPRINT("Module->base %x Section->s_vaddr %x\n",
-             Module->base,
-             Section->s_vaddr);
-      (*Location) = (*Location) + Value - Module->base + Section->s_vaddr;
-      DPRINT("new %x\n", *Location);
+      ObAddEntryDirectory(Parent, ObjectBody, RemainingPath + 1);
     }
 
-  return TRUE;
+  return  STATUS_SUCCESS;
 }
 
 /*
- * FUNCTION: Get the name of a symbol from a loaded module by ordinal
+ * FUNCTION: Loads a kernel driver
  * ARGUMENTS:
- *      mod = module
- *      i = index of symbol
- *      name (OUT) = pointer to a string where the symbol name will be
- *                   stored
+ *         FileName = Driver to load
+ * RETURNS: Status
  */
 
-static void 
-LdrCOFFGetSymbolName(module *Module, unsigned int Idx, char *Name)
+NTSTATUS LdrLoadDriver(PUNICODE_STRING Filename)
 {
-  if (Module->sym_list[Idx].e.e_name[0] != 0)
+  PMODULE_OBJECT  ModuleObject;
+
+  ModuleObject = LdrLoadModule(Filename);
+  if (ModuleObject == 0)
     {
-      strncpy(Name, Module->sym_list[Idx].e.e_name, 8);
-      Name[8] = '\0';
+      return  STATUS_UNSUCCESSFUL;
     }
-  else
+
+  /* FIXME: should we dereference the ModuleObject here?  */
+
+  return IoInitializeDriver(ModuleObject->EntryPoint);
+}
+
+NTSTATUS LdrLoadGdiDriver (PUNICODE_STRING DriverName,
+                          PVOID *ImageAddress,
+                          PVOID *SectionPointer,
+                          PVOID *EntryPoint,
+                          PVOID *ExportSectionPointer)
+{
+  PMODULE_OBJECT  ModuleObject;
+
+  ModuleObject = LdrLoadModule(DriverName);
+  if (ModuleObject == 0)
     {
-      strcpy(Name, &Module->str_tab[Module->sym_list[Idx].e.e.e_offset]);
+      return  STATUS_UNSUCCESSFUL;
     }
+
+  if (ImageAddress)
+    *ImageAddress = ModuleObject->Base;
+
+//  if (SectionPointer)
+//    *SectionPointer = ModuleObject->
+
+  if (EntryPoint)
+    *EntryPoint = ModuleObject->EntryPoint;
+
+//  if (ExportSectionPointer)
+//    *ExportSectionPointer = ModuleObject->
+
+  return STATUS_SUCCESS;
 }
 
-/*
- * FUNCTION: Get the value of a module defined symbol
- * ARGUMENTS:
- *      mod = module
- *      i = index of symbol
- * RETURNS: The value of the symbol
- * NOTE: This fixes up references to known sections
- */
 
-static unsigned int 
-LdrCOFFGetSymbolValue(module *Module, unsigned int Idx)
+PMODULE_OBJECT
+LdrLoadModule(PUNICODE_STRING Filename)
 {
-  char Name[255];
+  PVOID ModuleLoadBase;
+  NTSTATUS Status;
+  HANDLE FileHandle;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  PMODULE_OBJECT  ModuleObject;
+  FILE_STANDARD_INFORMATION FileStdInfo;
 
-  LdrCOFFGetSymbolName(Module, Idx, Name);
-  DbgPrint("name %s ", Name);
-   
-  /*  Check if the symbol is a section we have relocated  */
-  if (strcmp(Name, ".text") == 0)
+  /*  Check for module already loaded  */
+  if ((ModuleObject = LdrOpenModule(Filename)) != NULL)
     {
-      return Module->text_base;
+      return  ModuleObject;
     }
-  if (strcmp(Name, ".data") == 0)
+
+  DPRINT("Loading Module %wZ...\n", Filename);
+
+  /*  Open the Module  */
+  InitializeObjectAttributes(&ObjectAttributes,
+                             Filename,
+                             0,
+                             NULL,
+                             NULL);
+  CHECKPOINT;
+  Status = NtOpenFile(&FileHandle,
+                      FILE_ALL_ACCESS,
+                      &ObjectAttributes,
+                      NULL, 0, 0);
+  CHECKPOINT;
+  if (!NT_SUCCESS(Status))
     {
-      return Module->data_base;
+      DbgPrint("Could not open module file: %wZ\n", Filename);
+      return  0;
     }
-  if (strcmp(Name, ".bss") == 0)
+  CHECKPOINT;
+
+  /*  Get the size of the file  */
+  Status = NtQueryInformationFile(FileHandle,
+                                  NULL,
+                                  &FileStdInfo,
+                                  sizeof(FileStdInfo),
+                                  FileStandardInformation);
+  if (!NT_SUCCESS(Status))
     {
-      return Module->bss_base;
+      DbgPrint("Could not get file size\n");
+      return  0;
     }
+  CHECKPOINT;
 
-  return Module->sym_list[Idx].e_value;
-}
-
-/*
- * FUNCTION: Get the address of a kernel symbol
- * ARGUMENTS:
- *      name = symbol name
- * RETURNS: The address of the symbol on success
- *          NULL on failure
- */
-
-static unsigned int  
-LdrCOFFGetKernelSymbolAddr(char *Name)
-{
-  int i = 0;
+  /*  Allocate nonpageable memory for driver  */
+  ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
+                                        FileStdInfo.EndOfFile.u.LowPart,
+                                        TAG_DRIVER_MEM);
 
-  while (symbol_table[i].name != NULL)
+  if (ModuleLoadBase == NULL)
     {
-      if (strcmp(symbol_table[i].name, Name) == 0)
-        {
-          return symbol_table[i].value;
-        }
-      i++;
+      DbgPrint("could not allocate memory for module");
+      return  0;
     }
-
-  return 0L;
-}
-
-static unsigned int 
-LdrCOFFGetSymbolValueByName(module *Module, 
-                            char *SymbolName,
-                            unsigned int Idx)
-{
-  unsigned int i;
-  char Name[255];
-   
-  DPRINT("LdrCOFFGetSymbolValueByName(sname %s, idx %x)\n", SymbolName, Idx);
+  CHECKPOINT;
    
-  for (i = 0; i < Module->nsyms; i++)
+  /*  Load driver into memory chunk  */
+  Status = NtReadFile(FileHandle, 
+                      0, 0, 0, 0, 
+                      ModuleLoadBase, 
+                      FileStdInfo.EndOfFile.u.LowPart, 
+                      0, 0);
+  if (!NT_SUCCESS(Status))
     {
-      LdrCOFFGetSymbolName(Module, i, Name);
-      DPRINT("Scanning %s Value %x\n", Name, Module->sym_list[i].e_value);
-      if (strcmp(Name, SymbolName) == 0)
-        {
-          DPRINT("Returning %x\n", Module->sym_list[i].e_value);
-          return Module->sym_list[i].e_value;
-        }
+      DbgPrint("could not read module file into memory");
+      ExFreePool(ModuleLoadBase);
+
+      return  0;
     }
+  CHECKPOINT;
 
-  return 0L;
-}
+  NtClose(FileHandle);
 
+  ModuleObject = LdrProcessModule(ModuleLoadBase, Filename);
 
+  /*  Cleanup  */
+  ExFreePool(ModuleLoadBase);
 
+  return  ModuleObject;
+}
 
-static NTSTATUS 
-LdrProcessPEDriver(HANDLE FileHandle, PIMAGE_DOS_HEADER DosHeader)
+NTSTATUS
+LdrProcessDriver(PVOID ModuleLoadBase, PCHAR FileName)
 {
-  return STATUS_NOT_IMPLEMENTED;
+   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?  */
+
+   return(IoInitializeDriver(ModuleObject->EntryPoint));
 }
 
-NTSTATUS 
-LdrLoadDriver(PUNICODE_STRING Filename)
-/*
- * FUNCTION: Loads a kernel driver
- * ARGUMENTS:
- *         FileName = Driver to load
- * RETURNS: Status
- */
+PMODULE_OBJECT
+LdrProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING ModuleName)
 {
-  char BlockBuffer[512];
-  NTSTATUS Status;
-  HANDLE FileHandle;
-  OBJECT_ATTRIBUTES FileObjectAttributes;
   PIMAGE_DOS_HEADER PEDosHeader;
 
-  /*  Open the Driver  */
-  InitializeObjectAttributes(&FileObjectAttributes,
-                             Filename, 
-                             0,
-                             NULL,
-                             NULL);
-  Status = ZwOpenFile(&FileHandle, 0, &FileObjectAttributes, NULL, 0, 0);
-  if (!NT_SUCCESS(Status))
+  /*  If MZ header exists  */
+  PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
+  if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
     {
-      return Status;
+      return LdrPEProcessModule(ModuleLoadBase, ModuleName);
     }
 
-  /*  Read first block of image to determine type  */
-  Status = ZwReadFile(FileHandle, 0, 0, 0, 0, BlockBuffer, 512, 0, 0);
-  if (!NT_SUCCESS(Status))
-    {
-      ZwClose(FileHandle);
-      return Status;
-    }    
+  DPRINT1("Module wasn't PE\n");
+  return 0;
+}
 
-  /*  If MZ header exists  */
-  PEDosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
-  if (PEDosHeader->e_magic == 0x54AD && PEDosHeader->e_lfanew != 0L)
+static PMODULE_OBJECT 
+LdrOpenModule(PUNICODE_STRING  Filename)
+{
+  NTSTATUS  Status;
+  WCHAR  NameBuffer[60];
+  UNICODE_STRING  ModuleName;
+  OBJECT_ATTRIBUTES  ObjectAttributes;
+  PMODULE_OBJECT  ModuleObject;
+  UNICODE_STRING RemainingPath;
+
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  if (wcsrchr(Filename->Buffer, '\\') != 0)
     {
-      Status = LdrProcessPEDriver(FileHandle, PEDosHeader);
-      if (!NT_SUCCESS(Status))
-        {
-          ZwClose(FileHandle);
-          return Status;
-        }
+      wcscat(NameBuffer, wcsrchr(Filename->Buffer, '\\') + 1);
     }
-  if (PEDosHeader->e_magic == 0x54AD)
+  else
     {
-      ZwClose(FileHandle);
-      return STATUS_NOT_IMPLEMENTED;
+      wcscat(NameBuffer, Filename->Buffer);
     }
-  else /*  Assume coff format and load  */
+  RtlInitUnicodeString (&ModuleName, NameBuffer);
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName, 
+                             0,
+                             NULL,
+                             NULL);
+
+  Status = ObFindObject(&ObjectAttributes,
+                        (PVOID *) &ModuleObject,
+                        &RemainingPath,
+                        NULL);
+  CHECKPOINT;
+  if (NT_SUCCESS(Status) && (RemainingPath.Buffer == NULL || *(RemainingPath.Buffer) == 0))
     {
-      Status = LdrCOFFProcessDriver(FileHandle);
-      if (!NT_SUCCESS(Status))
-        {
-          ZwClose(FileHandle);
-          return Status;
-        }
+      DPRINT("Module %wZ at %p\n", Filename, ModuleObject);
+      RtlFreeUnicodeString (&RemainingPath);
+
+      return  ModuleObject;
     }
 
-  return STATUS_NOT_IMPLEMENTED;
+  RtlFreeUnicodeString (&RemainingPath);
+
+  return  NULL;
 }
 
-static NTSTATUS 
-LdrProcessMZImage(HANDLE ProcessHandle, 
-                  HANDLE FileHandle, 
-                  PIMAGE_DOS_HEADER DosHeader)
+PVOID
+LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
+                    char *Name,
+                    unsigned short Hint)
 {
+  if (ModuleObject->Flags & MODULE_FLAG_PE)
+    {
+      return LdrPEGetExportAddress(ModuleObject, Name, Hint);
+    }
+  else
+    {
+      return 0;
+    }
+}
 
-  /* FIXME: map VDM into low memory  */
-  /* FIXME: Build/Load image sections  */
-   
-  return STATUS_NOT_IMPLEMENTED;
+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 NTSTATUS 
-LdrProcessPEImage(HANDLE ProcessHandle, 
-                  HANDLE FileHandle, 
-                  PIMAGE_DOS_HEADER DosHeader)
+
+static VOID
+LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
+                       PUNICODE_STRING FullName)
 {
-//  PIMAGE_NT_HEADERS PEHeader;
-//  PIMAGE_SECTION_HEADER Sections;
-
-  // FIXME: Check architechture
-  // FIXME: Build/Load image sections
-  // FIXME: do relocations code sections
-  // FIXME: resolve imports
-  // FIXME: do fixups
-   
-  return STATUS_NOT_IMPLEMENTED;
+   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);
 }
 
-/*
- * FUNCTION: Loads a PE executable into the specified process
- * ARGUMENTS:
- *        Filename = File to load
- *        ProcessHandle = handle 
- * RETURNS: Status
- */
 
-NTSTATUS 
-LdrLoadImage(PUNICODE_STRING Filename, HANDLE ProcessHandle)
+/*  ----------------------------------------------  PE Module support */
+
+PMODULE_OBJECT
+LdrPEProcessModule(PVOID ModuleLoadBase, PUNICODE_STRING FileName)
 {
-  char BlockBuffer[512];
-  NTSTATUS Status;
-  ULONG SectionSize;
-  HANDLE FileHandle;
-  HANDLE ThreadHandle;   
-  OBJECT_ATTRIBUTES FileObjectAttributes;
+  unsigned int DriverSize, Idx, Idx2;
+  ULONG RelocDelta, NumRelocs;
+  DWORD CurrentSize, TotalRelocs;
+  PVOID DriverBase;
+  PULONG PEMagic;
   PIMAGE_DOS_HEADER PEDosHeader;
-  CONTEXT Context;
-  HANDLE SectionHandle;
-  PVOID BaseAddress;
+  PIMAGE_FILE_HEADER PEFileHeader;
+  PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
+  PIMAGE_SECTION_HEADER PESectionHeaders;
+  PRELOCATION_DIRECTORY RelocDir;
+  PRELOCATION_ENTRY RelocEntry;
+  PMODULE_OBJECT  LibraryModuleObject;
+  HANDLE  ModuleHandle;
+  PMODULE_OBJECT  ModuleObject;
+  PVOID *ImportAddressList;
+  PULONG FunctionNameList;
+  PCHAR pName, SymbolNameBuf;
+  WORD Hint;
+  OBJECT_ATTRIBUTES  ObjectAttributes;
+  UNICODE_STRING  ModuleName;
+  WCHAR  NameBuffer[60];
+  MODULE_TEXT_SECTION* ModuleTextSection;
+
+  DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
 
-  /*  FIXME: should DLLs be named sections?  */
+  /*  Get header pointers  */
+  PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
+  PEMagic = (PULONG) ((unsigned int) ModuleLoadBase + 
+    PEDosHeader->e_lfanew);
+  PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase + 
+    PEDosHeader->e_lfanew + sizeof(ULONG));
+  PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase + 
+    PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
+  PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase + 
+    PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
+    sizeof(IMAGE_OPTIONAL_HEADER));
+  CHECKPOINT;
 
-  /*  Open the image file  */
-  InitializeObjectAttributes(&FileObjectAttributes,
-                             Filename, 
-                             0,
-                             NULL,
-                             NULL);
-  Status = ZwOpenFile(&FileHandle, 0, &FileObjectAttributes, NULL, 0, 0);
-  if (!NT_SUCCESS(Status))
+  /*  Check file magic numbers  */
+  if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
     {
-      return Status;
+      DbgPrint("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
+      return 0;
     }
-
-  /*  Read first block of image to determine type  */
-  Status = ZwReadFile(FileHandle, 0, 0, 0, 0, BlockBuffer, 512, 0, 0);
-  if (!NT_SUCCESS(Status))
+  if (PEDosHeader->e_lfanew == 0)
+    {
+      DbgPrint("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
+      return 0;
+    }
+  if (*PEMagic != IMAGE_PE_MAGIC)
+    {
+      DbgPrint("Incorrect PE magic: %08x\n", *PEMagic);
+      return 0;
+    }
+  if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
     {
-      ZwClose(FileHandle);
-      return Status;
-    }    
+      DbgPrint("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
+      return 0;
+    }
+  CHECKPOINT;
 
-  /*  If MZ header exists  */
-  PEDosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
-  if (PEDosHeader->e_magic == 0x54AD && PEDosHeader->e_lfanew != 0L)
+  /* FIXME: if image is fixed-address load, then fail  */
+
+  /* FIXME: check/verify OS version number  */
+
+  DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n", 
+         PEOptionalHeader->Magic,
+         PEOptionalHeader->MajorLinkerVersion,
+         PEOptionalHeader->MinorLinkerVersion);
+  DPRINT("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
+  CHECKPOINT;
+
+  /*  Determine the size of the module  */
+  DriverSize = PEOptionalHeader->SizeOfImage;
+  DPRINT("DriverSize %x\n",DriverSize);
+
+  /*  Allocate a virtual section for the module  */
+  DriverBase = MmAllocateSection(DriverSize);
+  if (DriverBase == 0)
+    {
+      DbgPrint("Failed to allocate a virtual section for driver\n");
+      return 0;
+    }
+   DbgPrint("DriverBase: %x\n", DriverBase);
+  CHECKPOINT;
+  /*  Copy headers over */
+  memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
+   CurrentSize = 0;
+  /*  Copy image sections into virtual section  */
+  for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
     {
-      Status = LdrProcessPEImage(ProcessHandle, 
-                                 FileHandle, 
-                                 PEDosHeader);
-      if (!NT_SUCCESS(Status))
+      //  Copy current section into current offset of virtual section
+      if (PESectionHeaders[Idx].Characteristics & 
+          (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
         {
-          return Status;
+          DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
+                 PESectionHeaders[Idx].VirtualAddress + DriverBase);
+           memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
+                  (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
+                  PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
         }
+      else
+        {
+          DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
+                 PESectionHeaders[Idx].VirtualAddress + DriverBase);
+          memset(PESectionHeaders[Idx].VirtualAddress + DriverBase, 
+                 '\0', PESectionHeaders[Idx].Misc.VirtualSize);
+
+        }
+      CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
+                              PEOptionalHeader->SectionAlignment);
+
+
+//      CurrentBase = (PVOID)((DWORD)CurrentBase + 
+  //      ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
+    //             PEOptionalHeader->SectionAlignment));
     }
-  else if (PEDosHeader->e_magic == 0x54AD)
+
+  /*  Perform relocation fixups  */
+  RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
+  RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
+    IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
+  DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n", 
+         DriverBase,
+         PEOptionalHeader->ImageBase,
+         RelocDelta);   
+  DPRINT("RelocDir %x\n",RelocDir);
+#if 1
+  for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
     {
-      Status = LdrProcessMZImage(ProcessHandle, 
-                                 FileHandle, 
-                                 PEDosHeader);
-      if (!NT_SUCCESS(Status))
+       if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
+        {
+           DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
+                  PESectionHeaders[Idx].Name,
+                  PESectionHeaders[Idx].PointerToRawData);
+           RelocDir = PESectionHeaders[Idx].PointerToRawData +
+             ModuleLoadBase;
+            CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
+           break;
+        }
+    }
+#else
+   RelocDir = RelocDir + (ULONG)DriverBase;
+   CurrentSize = PEOptionalHeader->DataDirectory
+                 [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
+#endif   
+  DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
+  TotalRelocs = 0;
+  while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
+    {
+      NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) / 
+        sizeof(WORD);
+/*      DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
+             RelocDir, 
+             RelocDir->VirtualAddress,
+             NumRelocs);*/
+      RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir + 
+        sizeof(RELOCATION_DIRECTORY));
+      for (Idx = 0; Idx < NumRelocs; Idx++)
         {
-          return Status;
+          ULONG Offset;
+          ULONG Type;
+          PDWORD RelocItem;
+          
+          Offset = RelocEntry[Idx].TypeOffset & 0xfff;
+          Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
+          RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress + 
+                               Offset);
+/*        DPRINT("  reloc at %08lx %x %s old:%08lx new:%08lx\n", 
+                 RelocItem,
+                 Type,
+                 Type ? "HIGHLOW" : "ABS",
+                 *RelocItem,
+                 (*RelocItem) + RelocDelta); */
+          if (Type == 3)
+            {
+              (*RelocItem) += RelocDelta;
+            }
+          else if (Type != 0)
+            {
+              DbgPrint("Unknown relocation type %x at %x\n",Type, &Type);
+              return 0;
+            }
         }
+      TotalRelocs += RelocDir->SizeOfBlock;
+      RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir + 
+        RelocDir->SizeOfBlock);
+//      DPRINT("TotalRelocs: %08lx  CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
     }
-  else /*  Assume bin format and load  */
+   
+  DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
+         PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
+         .VirtualAddress);
+  /*  Perform import fixups  */
+  if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
     {
-      FILE_STANDARD_INFORMATION FileStdInfo;
+      PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
 
-      /*  Get the size of the file for the section  */
-      Status = ZwQueryInformationFile(FileHandle,
-                                      NULL,
-                                      &FileStdInfo,
-                                      sizeof(FileStdInfo),
-                                      FileStandardInformation);
-      if (!NT_SUCCESS(Status))
-        {
-          ZwClose(FileHandle);
-          return Status;
-        }
+      SymbolNameBuf = ExAllocatePoolWithTag(NonPagedPool, 512, TAG_SYM_BUF);
 
-      /*  Create the section for the code  */
-      Status = ZwCreateSection(&SectionHandle,
-                               SECTION_ALL_ACCESS,
-                               NULL,
-                               NULL,
-                               PAGE_READWRITE,
-                               MEM_COMMIT,
-                               FileHandle);
-      ZwClose(FileHandle);
-      if (!NT_SUCCESS(Status))
+      /*  Process each import module  */
+      ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
+        ((DWORD)DriverBase + PEOptionalHeader->
+          DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
+      DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
+      while (ImportModuleDirectory->dwRVAModuleName)
         {
-          return Status;
-        }
+          /*  Check to make sure that import lib is kernel  */
+          pName = (PCHAR) DriverBase + 
+            ImportModuleDirectory->dwRVAModuleName;
+          wcscpy(NameBuffer, MODULE_ROOT_NAME);
+          for (Idx = 0; NameBuffer[Idx] != 0; Idx++)
+            ;
+          for (Idx2 = 0; pName[Idx2] != '\0'; Idx2++)
+            {
+              NameBuffer[Idx + Idx2] = (WCHAR) pName[Idx2];
+            }
+          NameBuffer[Idx + Idx2] = 0;
+          RtlInitUnicodeString (&ModuleName, NameBuffer);
+          DPRINT("Import module: %wZ\n", &ModuleName);
 
-      /*  Map a view of the section into the desired process  */
-      BaseAddress = (PVOID)0x10000;
-      SectionSize = GET_LARGE_INTEGER_LOW_PART(FileStdInfo.AllocationSize);
-      Status = ZwMapViewOfSection(SectionHandle,
-                                  ProcessHandle,
-                                  &BaseAddress,
-                                  0,
-                                  SectionSize,
-                                  NULL,
-                                  &SectionSize,
-                                  0,
-                                  MEM_COMMIT,
-                                  PAGE_READWRITE);
-      if (!NT_SUCCESS(Status))
-        {
-          /* FIXME: destroy the section here  */
+          LibraryModuleObject = LdrLoadModule(&ModuleName);
+          if (LibraryModuleObject == 0)
+            {
+              DbgPrint("Unknown import module: %wZ\n", &ModuleName);
+            }
+          /*  Get the import address list  */
+          ImportAddressList = (PVOID *) ((DWORD)DriverBase + 
+            ImportModuleDirectory->dwRVAFunctionAddressList);
 
-          return Status;
+          /*  Get the list of functions to import  */
+          if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
+            {
+              FunctionNameList = (PULONG) ((DWORD)DriverBase + 
+                ImportModuleDirectory->dwRVAFunctionNameList);
+            }
+          else
+            {
+              FunctionNameList = (PULONG) ((DWORD)DriverBase + 
+                ImportModuleDirectory->dwRVAFunctionAddressList);
+            }
+          /*  Walk through function list and fixup addresses  */
+          while (*FunctionNameList != 0L)
+            {
+              if ((*FunctionNameList) & 0x80000000) // hint
+                {
+                  pName = NULL;
+
+
+                  Hint = (*FunctionNameList) & 0xffff;
+                }
+              else // hint-name
+                {
+                  pName = (PCHAR)((DWORD)DriverBase + 
+                                  *FunctionNameList + 2);
+                  Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
+                }
+              DPRINT("  Hint:%04x  Name:%s\n", Hint, pName);
+
+              /*  Fixup the current import symbol  */
+              if (LibraryModuleObject != NULL)
+                {
+                  *ImportAddressList = LdrGetExportAddress(LibraryModuleObject, 
+                                                           pName, 
+                                                           Hint);
+                }
+              else
+                {
+                   DbgPrint("Unresolved kernel symbol: %s\n", pName);
+                  return(NULL);
+                }
+              ImportAddressList++;
+              FunctionNameList++;
+            }
+          ImportModuleDirectory++;
         }
-   
-      /*  Setup the context for the initial thread  */
-      memset(&Context,0,sizeof(CONTEXT));
-      Context.SegSs = USER_DS;
-      Context.Esp = 0x2000;
-      Context.EFlags = 0x202;
-      Context.SegCs = USER_CS;
-      Context.Eip = 0x10000;
-      Context.SegDs = USER_DS;
-      Context.SegEs = USER_DS;
-      Context.SegFs = USER_DS;
-      Context.SegGs = USER_DS;
-   
-      /*  Create the stack for the process  */
-      BaseAddress = (PVOID) 0x1000;
-      SectionSize = 0x1000;
-      Status = ZwAllocateVirtualMemory(ProcessHandle,
-                                       &BaseAddress,
-                                       0,
-                                       &SectionSize,
-                                       MEM_COMMIT,
-                                       PAGE_READWRITE);
-      if (!NT_SUCCESS(Status))
-        {
-          /* FIXME: unmap the section here  */
-          /* FIXME: destroy the section here  */
 
-          return Status;
-        }
-   
-      /*  Create the initial thread  */
-      Status = ZwCreateThread(&ThreadHandle,
-                              THREAD_ALL_ACCESS,
-                              NULL,
-                              ProcessHandle,
-                              NULL,
-                              &Context,
-                              NULL,
-                              FALSE);
-      if (!NT_SUCCESS(Status))
-        {
-          /* FIXME: destroy the stack memory block here  */
-          /* FIXME: unmap the section here  */
-          /* FIXME: destroy the section here  */
+      ExFreePool(SymbolNameBuf);
+    }
+
+  /*  Create ModuleName string  */
+  wcscpy(NameBuffer, MODULE_ROOT_NAME);
+  if (wcsrchr(FileName->Buffer, '\\') != 0)
+    {
+      wcscat(NameBuffer, wcsrchr(FileName->Buffer, '\\') + 1);
+    }
+  else
+    {
+      wcscat(NameBuffer, FileName->Buffer);
+    }
+  RtlInitUnicodeString (&ModuleName, NameBuffer);
+  DbgPrint("Module name is: %wZ\n", &ModuleName);
 
-          return Status;
+  /*  Initialize ObjectAttributes for ModuleObject  */
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &ModuleName,
+                             0,
+                             NULL,
+                             NULL);
+
+  /*  Create module object  */
+  ModuleHandle = 0;
+  ModuleObject = ObCreateObject(&ModuleHandle,
+                                STANDARD_RIGHTS_REQUIRED,
+                                &ObjectAttributes,
+                                IoDriverObjectType);
+
+   /*  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;
+  DPRINT("entrypoint at %x\n", ModuleObject->EntryPoint);
+
+  ModuleObject->Image.PE.FileHeader =
+    (PIMAGE_FILE_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG));
+
+  DPRINT("FileHeader at %x\n", ModuleObject->Image.PE.FileHeader);
+  ModuleObject->Image.PE.OptionalHeader = 
+    (PIMAGE_OPTIONAL_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
+    sizeof(IMAGE_FILE_HEADER));
+  DPRINT("OptionalHeader at %x\n", ModuleObject->Image.PE.OptionalHeader);
+  ModuleObject->Image.PE.SectionList = 
+    (PIMAGE_SECTION_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
+    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
+LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
+                      char *Name,
+                      unsigned short Hint)
+{
+  WORD  Idx;
+  PVOID  ExportAddress;
+  PWORD  OrdinalList;
+  PDWORD  FunctionList, NameList;
+   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;
+     }
+
+
+   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 < ExportDir->NumberOfNames; Idx++)
+        {
+#if 0
+          DPRINT("  Name:%s  NameList[%d]:%s\n", 
+                 Name, 
+                 Idx, 
+                 (DWORD) ModuleObject->Base + NameList[Idx]);
+
+#endif
+          if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
+            {
+              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;
+            }
         }
     }
-  /* FIXME: {else} could check for a.out, ELF, COFF, etc. images here... */
+  else  /*  use hint  */
+    {
+      ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
+        FunctionList[Hint - ExportDir->Base]);
+    }
 
-  return Status;
+   if (ExportAddress == 0)
+     {
+       DbgPrint("Export not found for %d:%s\n",
+                Hint,
+                Name != NULL ? Name : "(Ordinal)");
+       KeBugCheck(0);
+     }
+
+   return ExportAddress;
+}
+
+
+static PMODULE_OBJECT
+LdrPEGetModuleObject(PUNICODE_STRING ModuleName)
+{
+   PLIST_ENTRY Entry;
+   PMODULE_OBJECT Module;
+
+   DPRINT("LdrPEGetModuleObject (ModuleName %wZ)\n",
+          ModuleName);
+
+   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 */