branch update for HEAD-2003050101
[reactos.git] / ntoskrnl / ldr / loader.c
1 /* $Id$
2  * 
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/ldr/loader.c
6  * PURPOSE:         Loaders for PE executables
7  * PROGRAMMERS:     Jean Michault
8  *                  Rex Jolliff (rex@lvcablemodem.com)
9  *                  Jason Filby (jasonfilby@yahoo.com)
10  *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
11  * UPDATE HISTORY:
12  *   DW   22/05/98   Created
13  *   RJJ  10/12/98   Completed image loader function and added hooks for MZ/PE
14  *   RJJ  10/12/98   Built driver loader function and added hooks for PE/COFF
15  *   RJJ  10/12/98   Rolled in David's code to load COFF drivers
16  *   JM   14/12/98   Built initial PE user module loader
17  *   RJJ  06/03/99   Moved user PE loader into NTDLL
18  *   JF   26/01/2000 Recoded some parts to retrieve export details correctly
19  *   DW   27/06/2000 Removed redundant header files
20  *   CSH  11/04/2001 Added automatic loading of module symbols if they exist
21  *   KJK  02/04/2003 Nebbet-ized a couple of type names
22  */
23
24
25 /* INCLUDES *****************************************************************/
26
27 #include <limits.h>
28 #include <ddk/ntddk.h>
29 #include <roscfg.h>
30 #include <internal/module.h>
31 #include <internal/ntoskrnl.h>
32 #include <internal/kd.h>
33 #include <internal/io.h>
34 #include <internal/mm.h>
35 #include <internal/ps.h>
36 #include <internal/ldr.h>
37 #include <internal/pool.h>
38 #include <internal/kd.h>
39 #include <ntos/minmax.h>
40
41 #ifdef HALDBG
42 #include <internal/ntosdbg.h>
43 #else
44 #define ps(args...)
45 #endif
46
47 #define NDEBUG
48 #include <internal/debug.h>
49
50 /* GLOBALS *******************************************************************/
51
52 LIST_ENTRY ModuleListHead;
53 KSPIN_LOCK ModuleListLock;
54
55 LIST_ENTRY ModuleTextListHead;
56 #ifndef LIBCAPTIVE
57 STATIC MODULE_TEXT_SECTION NtoskrnlTextSection;
58 STATIC MODULE_TEXT_SECTION LdrHalTextSection;
59 #endif /* LIBCAPTIVE */
60 ULONG_PTR LdrHalBase;
61
62 #define TAG_DRIVER_MEM  TAG('D', 'R', 'V', 'M')
63
64 /* FORWARD DECLARATIONS ******************************************************/
65
66 NTSTATUS
67 LdrProcessModule(PVOID ModuleLoadBase,
68                  PUNICODE_STRING ModuleName,
69                  PMODULE_OBJECT *ModuleObject);
70
71 PVOID
72 LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
73                     char *Name,
74                     unsigned short Hint);
75
76 #ifndef LIBCAPTIVE
77 static
78 #endif /* LIBCAPTIVE */
79 VOID
80 LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
81                         PUNICODE_STRING FullName);
82
83 static LONG
84 LdrpCompareModuleNames(IN PUNICODE_STRING String1,
85                        IN PUNICODE_STRING String2);
86
87
88 /*  PE Driver load support  */
89 static NTSTATUS LdrPEProcessModule(PVOID ModuleLoadBase,
90                                    PUNICODE_STRING FileName,
91                                    PMODULE_OBJECT *ModuleObject);
92 static PVOID
93 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
94                       PCHAR Name,
95                       USHORT Hint);
96
97 #ifndef LIBCAPTIVE
98 static PVOID
99 LdrSafePEGetExportAddress(PVOID ImportModuleBase,
100                           PCHAR Name,
101                           USHORT Hint);
102 #endif /* LIBCAPTIVE */
103
104 static PVOID
105 LdrPEFixupForward(PCHAR ForwardName);
106
107
108 /* FUNCTIONS *****************************************************************/
109
110 #ifndef LIBCAPTIVE
111
112 VOID
113 LdrInitDebug(PLOADER_MODULE Module, PWCH Name)
114 {
115   PLIST_ENTRY current_entry;
116   MODULE_TEXT_SECTION* current;
117
118   current_entry = ModuleTextListHead.Flink;
119   while (current_entry != &ModuleTextListHead)
120     {
121       current = 
122         CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
123       if (wcscmp(current->Name, Name) == 0)
124         {
125           break;
126         }
127       current_entry = current_entry->Flink;
128     }
129
130   if (current_entry == &ModuleTextListHead)
131     {
132       return;
133     }
134 }
135
136 VOID
137 LdrInit1(VOID)
138 {
139   PIMAGE_DOS_HEADER DosHeader;
140   PIMAGE_FILE_HEADER FileHeader;
141   PIMAGE_OPTIONAL_HEADER OptionalHeader;
142   PIMAGE_SECTION_HEADER SectionList;
143
144   InitializeListHead(&ModuleTextListHead);
145
146   /* Setup ntoskrnl.exe text section */
147   DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
148   FileHeader =
149     (PIMAGE_FILE_HEADER) ((DWORD)KERNEL_BASE + 
150                           DosHeader->e_lfanew + sizeof(ULONG));
151   OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
152     ((DWORD)FileHeader + sizeof(IMAGE_FILE_HEADER));
153   SectionList = (PIMAGE_SECTION_HEADER)
154     ((DWORD)OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
155   NtoskrnlTextSection.Base = KERNEL_BASE;
156   NtoskrnlTextSection.Length = SectionList[0].Misc.VirtualSize +
157     SectionList[0].VirtualAddress;
158   NtoskrnlTextSection.Name = KERNEL_MODULE_NAME;
159   NtoskrnlTextSection.OptionalHeader = OptionalHeader;
160   InsertTailList(&ModuleTextListHead, &NtoskrnlTextSection.ListEntry);
161
162   /* Setup hal.dll text section */
163   DosHeader = (PIMAGE_DOS_HEADER)LdrHalBase;
164   FileHeader =
165     (PIMAGE_FILE_HEADER) ((DWORD)LdrHalBase + 
166                           DosHeader->e_lfanew + sizeof(ULONG));
167   OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
168     ((DWORD)FileHeader + sizeof(IMAGE_FILE_HEADER));
169   SectionList = (PIMAGE_SECTION_HEADER)
170     ((DWORD)OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
171   LdrHalTextSection.Base = LdrHalBase;
172   LdrHalTextSection.Length = SectionList[0].Misc.VirtualSize +
173     SectionList[0].VirtualAddress;
174   LdrHalTextSection.Name = HAL_MODULE_NAME;
175   LdrHalTextSection.OptionalHeader = OptionalHeader;
176   InsertTailList(&ModuleTextListHead, &LdrHalTextSection.ListEntry);
177
178   /* Hook for KDB on initialization of the loader. */
179   KDB_LOADERINIT_HOOK(&NtoskrnlTextSection, &LdrHalTextSection);
180 }
181
182
183 VOID
184 LdrInitModuleManagement(VOID)
185 {
186   PIMAGE_DOS_HEADER DosHeader;
187   PMODULE_OBJECT ModuleObject;
188
189   /* Initialize the module list and spinlock */
190   InitializeListHead(&ModuleListHead);
191   KeInitializeSpinLock(&ModuleListLock);
192
193   /* Create module object for NTOSKRNL */
194   ModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
195   assert(ModuleObject != NULL);
196   RtlZeroMemory(ModuleObject, sizeof(MODULE_OBJECT));
197
198   /* Initialize ModuleObject data */
199   ModuleObject->Base = (PVOID) KERNEL_BASE;
200   ModuleObject->Flags = MODULE_FLAG_PE;
201   RtlCreateUnicodeString(&ModuleObject->FullName,
202                          KERNEL_MODULE_NAME);
203   LdrpBuildModuleBaseName(&ModuleObject->BaseName,
204                           &ModuleObject->FullName);
205
206   DosHeader = (PIMAGE_DOS_HEADER) KERNEL_BASE;
207   ModuleObject->Image.PE.FileHeader =
208     (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
209     DosHeader->e_lfanew + sizeof(ULONG));
210   ModuleObject->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
211     ((DWORD)ModuleObject->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
212   ModuleObject->Image.PE.SectionList = (PIMAGE_SECTION_HEADER)
213     ((DWORD)ModuleObject->Image.PE.OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
214   ModuleObject->EntryPoint = (PVOID) ((DWORD) ModuleObject->Base +
215     ModuleObject->Image.PE.OptionalHeader->AddressOfEntryPoint);
216   DPRINT("ModuleObject:%08x  entrypoint at %x\n", ModuleObject, ModuleObject->EntryPoint);
217   ModuleObject->Length = ModuleObject->Image.PE.OptionalHeader->SizeOfImage;
218   ModuleObject->TextSection = &NtoskrnlTextSection;
219
220   InsertTailList(&ModuleListHead,
221                  &ModuleObject->ListEntry);
222
223   /* Create module object for HAL */
224   ModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
225   assert(ModuleObject != NULL);
226   RtlZeroMemory(ModuleObject, sizeof(MODULE_OBJECT));
227
228   /* Initialize ModuleObject data */
229   ModuleObject->Base = (PVOID) LdrHalBase;
230   ModuleObject->Flags = MODULE_FLAG_PE;
231
232   RtlCreateUnicodeString(&ModuleObject->FullName,
233                          HAL_MODULE_NAME);
234   LdrpBuildModuleBaseName(&ModuleObject->BaseName,
235                           &ModuleObject->FullName);
236
237   DosHeader = (PIMAGE_DOS_HEADER) LdrHalBase;
238   ModuleObject->Image.PE.FileHeader =
239     (PIMAGE_FILE_HEADER) ((DWORD) ModuleObject->Base +
240     DosHeader->e_lfanew + sizeof(ULONG));
241   ModuleObject->Image.PE.OptionalHeader = (PIMAGE_OPTIONAL_HEADER)
242     ((DWORD)ModuleObject->Image.PE.FileHeader + sizeof(IMAGE_FILE_HEADER));
243   ModuleObject->Image.PE.SectionList = (PIMAGE_SECTION_HEADER)
244     ((DWORD)ModuleObject->Image.PE.OptionalHeader + sizeof(IMAGE_OPTIONAL_HEADER));
245   ModuleObject->EntryPoint = (PVOID) ((DWORD) ModuleObject->Base +
246     ModuleObject->Image.PE.OptionalHeader->AddressOfEntryPoint);
247   DPRINT("ModuleObject:%08x  entrypoint at %x\n", ModuleObject, ModuleObject->EntryPoint);
248   ModuleObject->Length = ModuleObject->Image.PE.OptionalHeader->SizeOfImage;
249   ModuleObject->TextSection = &LdrHalTextSection;
250
251   InsertTailList(&ModuleListHead,
252                  &ModuleObject->ListEntry);
253 }
254
255 NTSTATUS
256 LdrpLoadImage(PUNICODE_STRING DriverName,
257               PVOID *ModuleBase,
258               PVOID *SectionPointer,
259               PVOID *EntryPoint,
260               PVOID *ExportSectionPointer)
261 {
262   PMODULE_OBJECT ModuleObject;
263   NTSTATUS Status;
264
265   ModuleObject = LdrGetModuleObject(DriverName);
266   if (ModuleObject == NULL)
267     {
268       Status = LdrLoadModule(DriverName, &ModuleObject);
269       if (!NT_SUCCESS(Status))
270         {
271           return(Status);
272         }
273     }
274
275   if (ModuleBase)
276     *ModuleBase = ModuleObject->Base;
277
278 //  if (SectionPointer)
279 //    *SectionPointer = ModuleObject->
280
281   if (EntryPoint)
282     *EntryPoint = ModuleObject->EntryPoint;
283
284 //  if (ExportSectionPointer)
285 //    *ExportSectionPointer = ModuleObject->
286
287   return(STATUS_SUCCESS);
288 }
289
290
291 NTSTATUS
292 LdrpUnloadImage(PVOID ModuleBase)
293 {
294   return(STATUS_NOT_IMPLEMENTED);
295 }
296
297
298 NTSTATUS
299 LdrpLoadAndCallImage(PUNICODE_STRING ModuleName)
300 {
301   PDRIVER_INITIALIZE DriverEntry;
302   PMODULE_OBJECT ModuleObject;
303   NTSTATUS Status;
304
305   ModuleObject = LdrGetModuleObject(ModuleName);
306   if (ModuleObject != NULL)
307     {
308       return(STATUS_IMAGE_ALREADY_LOADED);
309     }
310
311   Status = LdrLoadModule(ModuleName, &ModuleObject);
312   if (!NT_SUCCESS(Status))
313     {
314       return(Status);
315     }
316
317   DriverEntry = (PDRIVER_INITIALIZE)ModuleObject->EntryPoint;
318
319   Status = DriverEntry(NULL, NULL);
320   if (!NT_SUCCESS(Status))
321     {
322       LdrUnloadModule(ModuleObject);
323     }
324
325   return(Status);
326 }
327
328
329 NTSTATUS
330 LdrLoadModule(PUNICODE_STRING Filename,
331               PMODULE_OBJECT *ModuleObject)
332 {
333   PVOID ModuleLoadBase;
334   NTSTATUS Status;
335   HANDLE FileHandle;
336   OBJECT_ATTRIBUTES ObjectAttributes;
337   PMODULE_OBJECT Module;
338   FILE_STANDARD_INFORMATION FileStdInfo;
339   IO_STATUS_BLOCK IoStatusBlock;
340
341   *ModuleObject = NULL;
342
343   DPRINT("Loading Module %wZ...\n", Filename);
344
345   /*  Open the Module  */
346   InitializeObjectAttributes(&ObjectAttributes,
347                              Filename,
348                              0,
349                              NULL,
350                              NULL);
351   CHECKPOINT;
352   Status = NtOpenFile(&FileHandle,
353                       FILE_ALL_ACCESS,
354                       &ObjectAttributes,
355                       &IoStatusBlock,
356                       0,
357                       FILE_SYNCHRONOUS_IO_NONALERT);
358   CHECKPOINT;
359   if (!NT_SUCCESS(Status))
360     {
361       CPRINT("Could not open module file: %wZ\n", Filename);
362       return(Status);
363     }
364   CHECKPOINT;
365
366   /*  Get the size of the file  */
367   Status = NtQueryInformationFile(FileHandle,
368                                   &IoStatusBlock,
369                                   &FileStdInfo,
370                                   sizeof(FileStdInfo),
371                                   FileStandardInformation);
372   if (!NT_SUCCESS(Status))
373     {
374       CPRINT("Could not get file size\n");
375       NtClose(FileHandle);
376       return(Status);
377     }
378   CHECKPOINT;
379
380   /*  Allocate nonpageable memory for driver  */
381   ModuleLoadBase = ExAllocatePoolWithTag(NonPagedPool,
382                                          FileStdInfo.EndOfFile.u.LowPart,
383                                          TAG_DRIVER_MEM);
384   if (ModuleLoadBase == NULL)
385     {
386       CPRINT("Could not allocate memory for module");
387       NtClose(FileHandle);
388       return(STATUS_INSUFFICIENT_RESOURCES);
389     }
390   CHECKPOINT;
391
392   /*  Load driver into memory chunk  */
393   Status = NtReadFile(FileHandle,
394                       0, 0, 0,
395                       &IoStatusBlock,
396                       ModuleLoadBase,
397                       FileStdInfo.EndOfFile.u.LowPart,
398                       0, 0);
399   if (!NT_SUCCESS(Status))
400     {
401       CPRINT("Could not read module file into memory");
402       ExFreePool(ModuleLoadBase);
403       NtClose(FileHandle);
404       return(Status);
405     }
406   CHECKPOINT;
407
408   NtClose(FileHandle);
409
410   Status = LdrProcessModule(ModuleLoadBase,
411                             Filename,
412                             &Module);
413   if (!NT_SUCCESS(Status))
414     {
415       CPRINT("Could not process module");
416       ExFreePool(ModuleLoadBase);
417       return(Status);
418     }
419
420   /*  Cleanup  */
421   ExFreePool(ModuleLoadBase);
422
423   *ModuleObject = Module;
424
425   /* Hook for KDB on loading a driver. */
426   KDB_LOADDRIVER_HOOK(Filename, Module);
427
428   return(STATUS_SUCCESS);
429 }
430
431 #endif /* LIBCAPTIVE */
432
433 NTSTATUS
434 LdrUnloadModule(PMODULE_OBJECT ModuleObject)
435 {
436   KIRQL Irql;
437
438   /* Remove the module from the module list */
439   KeAcquireSpinLock(&ModuleListLock,&Irql);
440   RemoveEntryList(&ModuleObject->ListEntry);
441   KeReleaseSpinLock(&ModuleListLock, Irql);
442
443   /* Hook for KDB on unloading a driver. */
444   KDB_UNLOADDRIVER_HOOK(ModuleObject);
445
446   /* Free text section */
447   if (ModuleObject->TextSection != NULL)
448     {
449       ExFreePool(ModuleObject->TextSection->Name);
450       RemoveEntryList(&ModuleObject->TextSection->ListEntry);
451       ExFreePool(ModuleObject->TextSection);
452       ModuleObject->TextSection = NULL;
453     }
454
455   /* Free module section */
456 //  MmFreeSection(ModuleObject->Base);
457
458   ExFreePool(ModuleObject);
459
460   return(STATUS_SUCCESS);
461 }
462
463 #ifndef LIBCAPTIVE
464
465 NTSTATUS
466 LdrInitializeBootStartDriver(PVOID ModuleLoadBase,
467                              PCHAR FileName,
468                              ULONG ModuleLength)
469 {
470   PMODULE_OBJECT ModuleObject;
471   UNICODE_STRING ModuleName;
472   PDEVICE_NODE DeviceNode;
473   NTSTATUS Status;
474
475   WCHAR Buffer[MAX_PATH];
476   ULONG Length;
477   LPWSTR Start;
478   LPWSTR Ext;
479   PCHAR FileExt;
480   CHAR TextBuffer [256];
481   ULONG x, y, cx, cy;
482
483   HalQueryDisplayParameters(&x, &y, &cx, &cy);
484   RtlFillMemory(TextBuffer, x, ' ');
485   TextBuffer[x] = '\0';
486   HalSetDisplayParameters(0, y-1);
487   HalDisplayString(TextBuffer);
488
489   sprintf(TextBuffer, "Initializing %s...\n", FileName);
490   HalSetDisplayParameters(0, y-1);
491   HalDisplayString(TextBuffer);
492   HalSetDisplayParameters(cx, cy);
493
494   /*  Split the filename into base name and extension  */
495   FileExt = strrchr(FileName, '.');
496   if (FileExt != NULL)
497     Length = FileExt - FileName;
498   else
499     Length = strlen(FileName);
500
501   if ((FileExt != NULL) && (strcmp(FileExt, ".sym") == 0))
502     {
503       KDB_SYMBOLFILE_HOOK(ModuleLoadBase, FileName, Length);
504       return(STATUS_SUCCESS);
505     }
506   else if ((FileExt != NULL) && !(strcmp(FileExt, ".sys") == 0))
507     {
508       CPRINT("Ignoring non-driver file %s\n", FileName);
509       return STATUS_SUCCESS;
510     }
511
512   /* Use IopRootDeviceNode for now */
513   Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
514   if (!NT_SUCCESS(Status))
515     {
516       CPRINT("Driver load failed, status (%x)\n", Status);
517       return(Status);
518     }
519
520   RtlCreateUnicodeStringFromAsciiz(&ModuleName,
521                                    FileName);
522   Status = LdrProcessModule(ModuleLoadBase,
523                             &ModuleName,
524                             &ModuleObject);
525   RtlFreeUnicodeString(&ModuleName);
526   if (ModuleObject == NULL)
527     {
528       IopFreeDeviceNode(DeviceNode);
529       CPRINT("Driver load failed, status (%x)\n", Status);
530       return(STATUS_UNSUCCESSFUL);
531     }
532
533
534   /* Get the service name from the module name */
535   Start = wcsrchr(ModuleObject->BaseName.Buffer, L'\\');
536   if (Start == NULL)
537     Start = ModuleObject->BaseName.Buffer;
538   else
539     Start++;
540
541   Ext = wcsrchr(ModuleObject->BaseName.Buffer, L'.');
542   if (Ext != NULL)
543     Length = Ext - Start;
544   else
545     Length = wcslen(Start);
546
547   wcsncpy(Buffer, Start, Length);
548   Buffer[Length] = 0;
549   RtlCreateUnicodeString(&DeviceNode->ServiceName, Buffer);
550
551   Status = IopInitializeDriver(ModuleObject->EntryPoint,
552                                DeviceNode, FALSE);
553   if (!NT_SUCCESS(Status))
554     {
555       IopFreeDeviceNode(DeviceNode);
556       CPRINT("Driver load failed, status (%x)\n", Status);
557     }
558
559   return(Status);
560 }
561
562 #endif /* LIBCAPTIVE */
563
564 NTSTATUS
565 LdrProcessModule(PVOID ModuleLoadBase,
566                  PUNICODE_STRING ModuleName,
567                  PMODULE_OBJECT *ModuleObject)
568 {
569   PIMAGE_DOS_HEADER PEDosHeader;
570
571   /*  If MZ header exists  */
572   PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
573   if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
574     {
575       return LdrPEProcessModule(ModuleLoadBase,
576                                 ModuleName,
577                                 ModuleObject);
578     }
579
580   CPRINT("Module wasn't PE\n");
581   return STATUS_UNSUCCESSFUL;
582 }
583
584
585 PVOID
586 LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
587                     char *Name,
588                     unsigned short Hint)
589 {
590   if (ModuleObject->Flags & MODULE_FLAG_PE)
591     {
592       return LdrPEGetExportAddress(ModuleObject, Name, Hint);
593     }
594   else
595     {
596       return 0;
597     }
598 }
599
600 #ifndef LIBCAPTIVE
601
602 NTSTATUS
603 LdrpQueryModuleInformation(PVOID Buffer,
604                            ULONG Size,
605                            PULONG ReqSize)
606 {
607   PLIST_ENTRY current_entry;
608   PMODULE_OBJECT current;
609   ULONG ModuleCount = 0;
610   PSYSTEM_MODULES Smi;
611   ANSI_STRING AnsiName;
612   PCHAR p;
613   KIRQL Irql;
614
615   KeAcquireSpinLock(&ModuleListLock,&Irql);
616
617   /* calculate required size */
618   current_entry = ModuleListHead.Flink;
619   while (current_entry != (&ModuleListHead))
620     {
621       ModuleCount++;
622       current_entry = current_entry->Flink;
623     }
624
625   *ReqSize = sizeof(SYSTEM_MODULES)+
626     (ModuleCount - 1) * sizeof(SYSTEM_MODULE_INFORMATION);
627
628   if (Size < *ReqSize)
629     {
630       KeReleaseSpinLock(&ModuleListLock, Irql);
631       return(STATUS_INFO_LENGTH_MISMATCH);
632     }
633
634   /* fill the buffer */
635   memset(Buffer, '=', Size);
636
637   Smi = (PSYSTEM_MODULES)Buffer;
638   Smi->Count = ModuleCount;
639
640   ModuleCount = 0;
641   current_entry = ModuleListHead.Flink;
642   while (current_entry != (&ModuleListHead))
643     {
644       current = CONTAINING_RECORD(current_entry,MODULE_OBJECT,ListEntry);
645
646       Smi->Modules[ModuleCount].Reserved[0] = 0;                /* Always 0 */
647       Smi->Modules[ModuleCount].Reserved[1] = 0;                /* Always 0 */
648       Smi->Modules[ModuleCount].Base = current->Base;
649       Smi->Modules[ModuleCount].Size = current->Length;
650       Smi->Modules[ModuleCount].Flags = 0;              /* Flags ??? (GN) */
651       Smi->Modules[ModuleCount].Index = ModuleCount;
652       Smi->Modules[ModuleCount].Unknown = 0;
653       Smi->Modules[ModuleCount].LoadCount = 0; /* FIXME */
654
655       AnsiName.Length = 0;
656       AnsiName.MaximumLength = 256;
657       AnsiName.Buffer = Smi->Modules[ModuleCount].ImageName;
658       RtlUnicodeStringToAnsiString(&AnsiName,
659                                    &current->FullName,
660                                    FALSE);
661
662       p = strrchr(AnsiName.Buffer, '\\');
663       if (p == NULL)
664         {
665           Smi->Modules[ModuleCount].ModuleNameOffset = 0;
666         }
667       else
668         {
669           p++;
670           Smi->Modules[ModuleCount].ModuleNameOffset = p - AnsiName.Buffer;
671         }
672
673       ModuleCount++;
674       current_entry = current_entry->Flink;
675     }
676
677   KeReleaseSpinLock(&ModuleListLock, Irql);
678
679   return(STATUS_SUCCESS);
680 }
681
682 #endif /* LIBCAPTIVE */
683
684 #ifndef LIBCAPTIVE
685 static
686 #endif /* LIBCAPTIVE */
687 VOID
688 LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
689                         PUNICODE_STRING FullName)
690 {
691    UNICODE_STRING Name;
692    PWCHAR p;
693    PWCHAR q;
694
695    DPRINT("LdrpBuildModuleBaseName()\n");
696    DPRINT("FullName %wZ\n", FullName);
697
698    p = wcsrchr(FullName->Buffer, L'\\');
699    if (p == NULL)
700      {
701         p = FullName->Buffer;
702      }
703    else
704      {
705         p++;
706      }
707
708    DPRINT("p %S\n", p);
709
710    RtlCreateUnicodeString(&Name, p);
711
712    q = wcschr(Name.Buffer, L'.');
713    if (q != NULL)
714      {
715         *q = (WCHAR)0;
716      }
717
718    DPRINT("p %S\n", p);
719
720    RtlCreateUnicodeString(BaseName, Name.Buffer);
721    RtlFreeUnicodeString(&Name);
722 }
723
724
725 static LONG
726 LdrpCompareModuleNames(IN PUNICODE_STRING String1,
727                        IN PUNICODE_STRING String2)
728 {
729   ULONG len1, len2, i;
730   PWCHAR s1, s2, p;
731   WCHAR  c1, c2;
732
733   if (String1 && String2)
734     {
735       /* Search String1 for last path component */
736       len1 = String1->Length / sizeof(WCHAR);
737       s1 = String1->Buffer;
738       for (i = 0, p = String1->Buffer; i < String1->Length; i = i + sizeof(WCHAR), p++)
739         {
740           if (*p == L'\\')
741             {
742               if (i == String1->Length - sizeof(WCHAR))
743                 {
744                   s1 = NULL;
745                   len1 = 0;
746                 }
747               else
748                 {
749                   s1 = p + 1;
750                   len1 = (String1->Length - i) / sizeof(WCHAR);
751                 }
752             }
753         }
754
755       /* Search String2 for last path component */
756       len2 = String2->Length / sizeof(WCHAR);
757       s2 = String2->Buffer;
758       for (i = 0, p = String2->Buffer; i < String2->Length; i = i + sizeof(WCHAR), p++)
759         {
760           if (*p == L'\\')
761             {
762               if (i == String2->Length - sizeof(WCHAR))
763                 {
764                   s2 = NULL;
765                   len2 = 0;
766                 }
767               else
768                 {
769                   s2 = p + 1;
770                   len2 = (String2->Length - i) / sizeof(WCHAR);
771                 }
772             }
773         }
774
775       /* Compare last path components */
776       if (s1 && s2)
777         {
778           while (1)
779             {
780               c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
781               c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
782               if ((c1 == 0 && c2 == L'.') || (c1 == L'.' && c2 == 0))
783                 return(0);
784               if (!c1 || !c2 || c1 != c2)
785                 return(c1 - c2);
786             }
787         }
788     }
789
790   return(0);
791 }
792
793
794 PMODULE_OBJECT
795 LdrGetModuleObject(PUNICODE_STRING ModuleName)
796 {
797   PMODULE_OBJECT Module;
798   PLIST_ENTRY Entry;
799   KIRQL Irql;
800
801   DPRINT("LdrpGetModuleObject(%wZ) called\n", ModuleName);
802
803   KeAcquireSpinLock(&ModuleListLock,&Irql);
804
805   Entry = ModuleListHead.Flink;
806   while (Entry != &ModuleListHead)
807     {
808       Module = CONTAINING_RECORD(Entry, MODULE_OBJECT, ListEntry);
809
810       DPRINT("Comparing %wZ and %wZ\n",
811              &Module->BaseName,
812              ModuleName);
813
814       if (!LdrpCompareModuleNames(&Module->BaseName, ModuleName))
815         {
816           DPRINT("Module %wZ\n", &Module->BaseName);
817           KeReleaseSpinLock(&ModuleListLock, Irql);
818           return(Module);
819         }
820
821       Entry = Entry->Flink;
822     }
823
824   KeReleaseSpinLock(&ModuleListLock, Irql);
825
826   DPRINT("Could not find module '%wZ'\n", ModuleName);
827
828   return(NULL);
829 }
830
831
832 /*  ----------------------------------------------  PE Module support */
833
834 static BOOL
835 PageNeedsWriteAccess(PVOID PageStart,
836                      PVOID DriverBase,
837                      PIMAGE_FILE_HEADER PEFileHeader,
838                      PIMAGE_SECTION_HEADER PESectionHeaders)
839 {
840   BOOL NeedsWriteAccess;
841   unsigned Idx;
842   ULONG Characteristics;
843   ULONG Length;
844   PVOID BaseAddress;
845
846   NeedsWriteAccess = FALSE;
847   /* Set the protections for the various parts of the driver */
848   for (Idx = 0; Idx < PEFileHeader->NumberOfSections && ! NeedsWriteAccess; Idx++)
849     {
850       Characteristics = PESectionHeaders[Idx].Characteristics;
851       if (!(Characteristics & IMAGE_SECTION_CHAR_CODE) ||
852           (Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
853            Characteristics & IMAGE_SECTION_CHAR_DATA ||
854            Characteristics & IMAGE_SECTION_CHAR_BSS))
855         {
856           Length = 
857               max(PESectionHeaders[Idx].Misc.VirtualSize,
858                   PESectionHeaders[Idx].SizeOfRawData);
859           BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
860           NeedsWriteAccess = BaseAddress < PageStart + PAGE_SIZE &&
861                              PageStart < (PVOID)((PCHAR) BaseAddress + Length);
862         }
863     }
864
865   return(NeedsWriteAccess);
866 }
867
868 static NTSTATUS
869 LdrPEProcessModule(PVOID ModuleLoadBase,
870                    PUNICODE_STRING FileName,
871                    PMODULE_OBJECT *ModuleObject)
872 {
873   unsigned int DriverSize, Idx;
874   ULONG RelocDelta, NumRelocs;
875   DWORD CurrentSize, TotalRelocs;
876   PVOID DriverBase;
877   PULONG PEMagic;
878   PIMAGE_DOS_HEADER PEDosHeader;
879   PIMAGE_FILE_HEADER PEFileHeader;
880   PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
881   PIMAGE_SECTION_HEADER PESectionHeaders;
882   PRELOCATION_DIRECTORY RelocDir;
883   PRELOCATION_ENTRY RelocEntry;
884   PMODULE_OBJECT  LibraryModuleObject;
885   PMODULE_OBJECT CreatedModuleObject;
886   PVOID *ImportAddressList;
887   PULONG FunctionNameList;
888   PCHAR pName;
889   WORD Hint;
890   UNICODE_STRING ModuleName;
891   UNICODE_STRING NameString;
892   WCHAR  NameBuffer[60];
893   MODULE_TEXT_SECTION* ModuleTextSection;
894   NTSTATUS Status;
895   KIRQL Irql;
896
897   DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
898
899   /*  Get header pointers  */
900   PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
901   PEMagic = (PULONG) ((unsigned int) ModuleLoadBase + 
902     PEDosHeader->e_lfanew);
903   PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase + 
904     PEDosHeader->e_lfanew + sizeof(ULONG));
905   PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase + 
906     PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
907   PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase + 
908     PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
909     sizeof(IMAGE_OPTIONAL_HEADER));
910   CHECKPOINT;
911
912   /*  Check file magic numbers  */
913   if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
914     {
915       CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
916       return STATUS_UNSUCCESSFUL;
917     }
918   if (PEDosHeader->e_lfanew == 0)
919     {
920       CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
921       return STATUS_UNSUCCESSFUL;
922     }
923   if (*PEMagic != IMAGE_PE_MAGIC)
924     {
925       CPRINT("Incorrect PE magic: %08x\n", *PEMagic);
926       return STATUS_UNSUCCESSFUL;
927     }
928   if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
929     {
930       CPRINT("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
931       return STATUS_UNSUCCESSFUL;
932     }
933   CHECKPOINT;
934
935   /* FIXME: if image is fixed-address load, then fail  */
936
937   /* FIXME: check/verify OS version number  */
938
939   DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n", 
940          PEOptionalHeader->Magic,
941          PEOptionalHeader->MajorLinkerVersion,
942          PEOptionalHeader->MinorLinkerVersion);
943   DPRINT("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
944   CHECKPOINT;
945
946   /*  Determine the size of the module  */
947   DriverSize = PEOptionalHeader->SizeOfImage;
948   DPRINT("DriverSize %x\n",DriverSize);
949
950   /*  Allocate a virtual section for the module  */
951   DriverBase = MmAllocateSection(DriverSize);
952   if (DriverBase == 0)
953     {
954       CPRINT("Failed to allocate a virtual section for driver\n");
955       return STATUS_UNSUCCESSFUL;
956     }
957   DbgPrint("DriverBase for %wZ: %x\n", FileName, DriverBase);
958   CHECKPOINT;
959   /*  Copy headers over */
960   memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
961    CurrentSize = 0;
962   /*  Copy image sections into virtual section  */
963   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
964     {
965       //  Copy current section into current offset of virtual section
966       if (PESectionHeaders[Idx].Characteristics & 
967           (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
968         {
969            DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
970                   PESectionHeaders[Idx].VirtualAddress + DriverBase);
971            memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
972                   (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
973                   PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData
974                   ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
975         }
976       else
977         {
978            DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
979                   PESectionHeaders[Idx].VirtualAddress + DriverBase);
980            memset(PESectionHeaders[Idx].VirtualAddress + DriverBase, 
981                   '\0', PESectionHeaders[Idx].Misc.VirtualSize);
982
983         }
984       CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
985                               PEOptionalHeader->SectionAlignment);
986
987
988 //      CurrentBase = (PVOID)((DWORD)CurrentBase + 
989   //      ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
990     //             PEOptionalHeader->SectionAlignment));
991     }
992
993   /*  Perform relocation fixups  */
994   RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
995   RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
996     IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
997   DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n", 
998          DriverBase,
999          PEOptionalHeader->ImageBase,
1000          RelocDelta);   
1001   DPRINT("RelocDir %x\n",RelocDir);
1002 #if 1
1003   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1004     {
1005        if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
1006          {
1007             DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
1008                    PESectionHeaders[Idx].Name,
1009                    PESectionHeaders[Idx].PointerToRawData);
1010             RelocDir = PESectionHeaders[Idx].PointerToRawData +
1011               ModuleLoadBase;
1012             CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
1013             break;
1014          }
1015     }
1016 #else
1017    RelocDir = RelocDir + (ULONG)DriverBase;
1018    CurrentSize = PEOptionalHeader->DataDirectory
1019                   [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
1020 #endif
1021   DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1022   TotalRelocs = 0;
1023   while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1024     {
1025       NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) / 
1026         sizeof(WORD);
1027 /*      DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
1028              RelocDir, 
1029              RelocDir->VirtualAddress,
1030              NumRelocs);*/
1031       RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir + 
1032         sizeof(RELOCATION_DIRECTORY));
1033       for (Idx = 0; Idx < NumRelocs; Idx++)
1034         {
1035            ULONG Offset;
1036            ULONG Type;
1037            PDWORD RelocItem;
1038            
1039            Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1040            Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1041            RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress + 
1042                                 Offset);
1043 /*         DPRINT("  reloc at %08lx %x %s old:%08lx new:%08lx\n", 
1044                   RelocItem,
1045                   Type,
1046                   Type ? "HIGHLOW" : "ABS",
1047                   *RelocItem,
1048                   (*RelocItem) + RelocDelta); */
1049           if (Type == 3)
1050             {
1051               (*RelocItem) += RelocDelta;
1052             }
1053           else if (Type != 0)
1054             {
1055               CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1056               return STATUS_UNSUCCESSFUL;
1057             }
1058         }
1059       TotalRelocs += RelocDir->SizeOfBlock;
1060       RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir + 
1061         RelocDir->SizeOfBlock);
1062 //      DPRINT("TotalRelocs: %08lx  CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
1063     }
1064    
1065   DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1066          PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1067          .VirtualAddress);
1068   /*  Perform import fixups  */
1069   if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1070     {
1071       PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1072
1073       /*  Process each import module  */
1074       ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1075         ((DWORD)DriverBase + PEOptionalHeader->
1076           DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1077       DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
1078       while (ImportModuleDirectory->dwRVAModuleName)
1079         {
1080           /*  Check to make sure that import lib is kernel  */
1081           pName = (PCHAR) DriverBase + 
1082             ImportModuleDirectory->dwRVAModuleName;
1083
1084           RtlCreateUnicodeStringFromAsciiz(&ModuleName, pName);
1085           DPRINT("Import module: %wZ\n", &ModuleName);
1086
1087           LibraryModuleObject = LdrGetModuleObject(&ModuleName);
1088           if (LibraryModuleObject == NULL)
1089             {
1090               DPRINT("Module '%wZ' not loaded yet\n", &ModuleName);
1091               wcscpy(NameBuffer, REACTOS_UCS2(L"\\SystemRoot\\system32\\drivers\\"));
1092               wcscat(NameBuffer, ModuleName.Buffer);
1093               RtlInitUnicodeString(&NameString, NameBuffer);
1094               Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1095               if (!NT_SUCCESS(Status))
1096                 {
1097                   wcscpy(NameBuffer, REACTOS_UCS2(L"\\SystemRoot\\system32\\"));
1098                   wcscat(NameBuffer, ModuleName.Buffer);
1099                   RtlInitUnicodeString(&NameString, NameBuffer);
1100                   Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1101                   if (!NT_SUCCESS(Status))
1102                     {
1103                       DPRINT1("Unknown import module: %wZ (Status %lx)\n", &ModuleName, Status);
1104                       return(Status);
1105                     }
1106                 }
1107             }
1108           /*  Get the import address list  */
1109           ImportAddressList = (PVOID *) ((DWORD)DriverBase + 
1110             ImportModuleDirectory->dwRVAFunctionAddressList);
1111
1112           /*  Get the list of functions to import  */
1113           if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1114             {
1115               FunctionNameList = (PULONG) ((DWORD)DriverBase + 
1116                 ImportModuleDirectory->dwRVAFunctionNameList);
1117             }
1118           else
1119             {
1120               FunctionNameList = (PULONG) ((DWORD)DriverBase + 
1121                 ImportModuleDirectory->dwRVAFunctionAddressList);
1122             }
1123           /*  Walk through function list and fixup addresses  */
1124           while (*FunctionNameList != 0L)
1125             {
1126               if ((*FunctionNameList) & 0x80000000) // hint
1127                 {
1128                   pName = NULL;
1129
1130
1131                   Hint = (*FunctionNameList) & 0xffff;
1132                 }
1133               else // hint-name
1134                 {
1135                   pName = (PCHAR)((DWORD)DriverBase + 
1136                                   *FunctionNameList + 2);
1137                   Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
1138                 }
1139               DPRINT("  Hint:%04x  Name:%s\n", Hint, pName);
1140
1141               /*  Fixup the current import symbol  */
1142               if (LibraryModuleObject != NULL)
1143                 {
1144                   *ImportAddressList = LdrGetExportAddress(LibraryModuleObject, 
1145                                                            pName, 
1146                                                            Hint);
1147                 }
1148               else
1149                 {
1150                   CPRINT("Unresolved kernel symbol: %s\n", pName);
1151                   return STATUS_UNSUCCESSFUL;
1152                 }
1153               ImportAddressList++;
1154               FunctionNameList++;
1155             }
1156
1157           RtlFreeUnicodeString(&ModuleName);
1158
1159           ImportModuleDirectory++;
1160         }
1161     }
1162
1163   /* Set the protections for the various parts of the driver */
1164   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1165     {
1166       ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
1167       ULONG Length;
1168       PVOID BaseAddress;
1169       PVOID PageAddress;
1170       if (Characteristics & IMAGE_SECTION_CHAR_CODE &&
1171           !(Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
1172             Characteristics & IMAGE_SECTION_CHAR_DATA ||
1173             Characteristics & IMAGE_SECTION_CHAR_BSS))
1174         {
1175           Length = 
1176               max(PESectionHeaders[Idx].Misc.VirtualSize,
1177                   PESectionHeaders[Idx].SizeOfRawData);
1178           BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
1179           PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
1180           if (! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1181             {
1182               MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1183             }
1184           PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1185           while ((PVOID)((PCHAR) PageAddress + PAGE_SIZE) <
1186                  (PVOID)((PCHAR) BaseAddress + Length))
1187             {
1188               MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1189               PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1190             }
1191           if (PageAddress < (PVOID)((PCHAR) BaseAddress + Length) &&
1192               ! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1193             {
1194               MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1195             }
1196         }
1197     }
1198
1199   /* Create the module */
1200   CreatedModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
1201   if (CreatedModuleObject == NULL)
1202     {
1203       return(STATUS_INSUFFICIENT_RESOURCES);
1204     }
1205
1206   RtlZeroMemory(CreatedModuleObject, sizeof(MODULE_OBJECT));
1207
1208    /*  Initialize ModuleObject data  */
1209   CreatedModuleObject->Base = DriverBase;
1210   CreatedModuleObject->Flags = MODULE_FLAG_PE;
1211   
1212   RtlCreateUnicodeString(&CreatedModuleObject->FullName,
1213                          FileName->Buffer);
1214   LdrpBuildModuleBaseName(&CreatedModuleObject->BaseName,
1215                           &CreatedModuleObject->FullName);
1216   
1217   CreatedModuleObject->EntryPoint = 
1218     (PVOID)((DWORD)DriverBase + 
1219             PEOptionalHeader->AddressOfEntryPoint);
1220   CreatedModuleObject->Length = DriverSize;
1221   DPRINT("EntryPoint at %x\n", CreatedModuleObject->EntryPoint);
1222   
1223   CreatedModuleObject->Image.PE.FileHeader =
1224     (PIMAGE_FILE_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG));
1225
1226   DPRINT("FileHeader at %x\n", CreatedModuleObject->Image.PE.FileHeader);
1227   CreatedModuleObject->Image.PE.OptionalHeader = 
1228     (PIMAGE_OPTIONAL_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1229     sizeof(IMAGE_FILE_HEADER));
1230   DPRINT("OptionalHeader at %x\n", CreatedModuleObject->Image.PE.OptionalHeader);
1231   CreatedModuleObject->Image.PE.SectionList = 
1232     (PIMAGE_SECTION_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1233     sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER));
1234   DPRINT("SectionList at %x\n", CreatedModuleObject->Image.PE.SectionList);
1235
1236   /* Insert module */
1237   KeAcquireSpinLock(&ModuleListLock, &Irql);
1238   InsertTailList(&ModuleListHead,
1239                  &CreatedModuleObject->ListEntry);
1240   KeReleaseSpinLock(&ModuleListLock, Irql);
1241
1242
1243   ModuleTextSection = ExAllocatePool(NonPagedPool, 
1244                                      sizeof(MODULE_TEXT_SECTION));
1245   assert(ModuleTextSection);
1246   RtlZeroMemory(ModuleTextSection, sizeof(MODULE_TEXT_SECTION));
1247   ModuleTextSection->Base = (ULONG)DriverBase;
1248   ModuleTextSection->Length = DriverSize;
1249   ModuleTextSection->Name = ExAllocatePool(NonPagedPool, 
1250         (wcslen(CreatedModuleObject->BaseName.Buffer) + 1) * sizeof(WCHAR));
1251   wcscpy(ModuleTextSection->Name, CreatedModuleObject->BaseName.Buffer);
1252   ModuleTextSection->OptionalHeader = 
1253     CreatedModuleObject->Image.PE.OptionalHeader;
1254   InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
1255
1256   CreatedModuleObject->TextSection = ModuleTextSection;
1257
1258   *ModuleObject = CreatedModuleObject;
1259
1260   DPRINT("Loading Module %wZ...\n", FileName);
1261
1262   if ((KdDebuggerEnabled == TRUE) && (KdDebugState & KD_DEBUG_GDB))
1263     {
1264       DPRINT("Module %wZ loaded at 0x%.08x.\n",
1265               FileName, CreatedModuleObject->Base);
1266     }
1267
1268   return STATUS_SUCCESS;
1269 }
1270
1271 #ifndef LIBCAPTIVE
1272
1273 PVOID
1274 LdrSafePEProcessModule(PVOID ModuleLoadBase,
1275                        PVOID DriverBase,
1276                        PVOID ImportModuleBase,
1277                        PULONG DriverSize)
1278 {
1279   unsigned int Idx;
1280   ULONG RelocDelta, NumRelocs;
1281   ULONG CurrentSize, TotalRelocs;
1282   PULONG PEMagic;
1283   PIMAGE_DOS_HEADER PEDosHeader;
1284   PIMAGE_FILE_HEADER PEFileHeader;
1285   PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
1286   PIMAGE_SECTION_HEADER PESectionHeaders;
1287   PRELOCATION_DIRECTORY RelocDir;
1288   PRELOCATION_ENTRY RelocEntry;
1289   PVOID *ImportAddressList;
1290   PULONG FunctionNameList;
1291   PCHAR pName;
1292   USHORT Hint;
1293
1294   ps("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
1295
1296   /*  Get header pointers  */
1297   PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
1298   PEMagic = (PULONG) ((unsigned int) ModuleLoadBase + 
1299     PEDosHeader->e_lfanew);
1300   PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase + 
1301     PEDosHeader->e_lfanew + sizeof(ULONG));
1302   PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase + 
1303     PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
1304   PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase + 
1305     PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
1306     sizeof(IMAGE_OPTIONAL_HEADER));
1307   CHECKPOINT;
1308
1309   /*  Check file magic numbers  */
1310   if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
1311     {
1312       return 0;
1313     }
1314   if (PEDosHeader->e_lfanew == 0)
1315     {
1316       return 0;
1317     }
1318   if (*PEMagic != IMAGE_PE_MAGIC)
1319     {
1320       return 0;
1321     }
1322   if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
1323     {
1324       return 0;
1325     }
1326
1327   ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n", 
1328          PEOptionalHeader->Magic,
1329          PEOptionalHeader->MajorLinkerVersion,
1330          PEOptionalHeader->MinorLinkerVersion);
1331   ps("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
1332
1333   /*  Determine the size of the module  */
1334   *DriverSize = PEOptionalHeader->SizeOfImage;
1335   ps("DriverSize %x\n",*DriverSize);
1336
1337   /*  Copy headers over */
1338   if (DriverBase != ModuleLoadBase)
1339     {
1340       memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
1341     }
1342
1343   ps("Hdr: 0x%X\n", (ULONG)PEOptionalHeader);
1344   ps("Hdr->SizeOfHeaders: 0x%X\n", (ULONG)PEOptionalHeader->SizeOfHeaders);
1345   ps("FileHdr->NumberOfSections: 0x%X\n", (ULONG)PEFileHeader->NumberOfSections);
1346
1347   /* Ntoskrnl.exe need no relocation fixups since it is linked to run at the same
1348      address as it is mapped */
1349   if (DriverBase != ModuleLoadBase)
1350     {
1351       CurrentSize = 0;
1352
1353   /*  Copy image sections into virtual section  */
1354   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1355     {
1356       //  Copy current section into current offset of virtual section
1357       if (PESectionHeaders[Idx].Characteristics & 
1358           (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
1359         {
1360           //ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1361           //PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1362           memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
1363                  (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
1364                  PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData ?
1365                    PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
1366         }
1367       else
1368         {
1369           ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1370              PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1371           memset(PESectionHeaders[Idx].VirtualAddress + DriverBase, 
1372                  '\0',
1373                  PESectionHeaders[Idx].Misc.VirtualSize);
1374         }
1375       CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
1376                               PEOptionalHeader->SectionAlignment);
1377     }
1378
1379   /*  Perform relocation fixups  */
1380   RelocDelta = (ULONG) DriverBase - PEOptionalHeader->ImageBase;
1381   RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
1382     IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
1383   ps("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n", 
1384          DriverBase,
1385          PEOptionalHeader->ImageBase,
1386          RelocDelta);   
1387   ps("RelocDir %x\n",RelocDir);
1388
1389   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1390     {
1391       if (PESectionHeaders[Idx].VirtualAddress == (ULONG)RelocDir)
1392         {
1393           DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
1394                  PESectionHeaders[Idx].Name,
1395                  PESectionHeaders[Idx].PointerToRawData);
1396           RelocDir = PESectionHeaders[Idx].PointerToRawData + ModuleLoadBase;
1397           CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
1398           break;
1399         }
1400     }
1401
1402   ps("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1403
1404   TotalRelocs = 0;
1405   while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1406     {
1407       NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) / 
1408         sizeof(USHORT);
1409       RelocEntry = (PRELOCATION_ENTRY)((ULONG)RelocDir + 
1410         sizeof(RELOCATION_DIRECTORY));
1411       for (Idx = 0; Idx < NumRelocs; Idx++)
1412         {
1413           ULONG Offset;
1414           ULONG Type;
1415           PULONG RelocItem;
1416
1417           Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1418           Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1419           RelocItem = (PULONG)(DriverBase + RelocDir->VirtualAddress + Offset);
1420           if (Type == 3)
1421             {
1422               (*RelocItem) += RelocDelta;
1423             }
1424           else if (Type != 0)
1425             {
1426               CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1427               return(0);
1428             }
1429         }
1430       TotalRelocs += RelocDir->SizeOfBlock;
1431       RelocDir = (PRELOCATION_DIRECTORY)((ULONG)RelocDir + 
1432         RelocDir->SizeOfBlock);
1433     }
1434
1435     ps("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1436          PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1437          .VirtualAddress);
1438   }
1439
1440   /*  Perform import fixups  */
1441   if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1442     {
1443       PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1444
1445       /*  Process each import module  */
1446       ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1447         ((ULONG)DriverBase + PEOptionalHeader->
1448           DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1449
1450       ps("Processeing import directory at %p\n", ImportModuleDirectory);
1451
1452       /*  Check to make sure that import lib is kernel  */
1453       pName = (PCHAR)DriverBase + ImportModuleDirectory->dwRVAModuleName;
1454
1455       ps("Import module: %s\n", pName);
1456
1457       /*  Get the import address list  */
1458       ImportAddressList = (PVOID *)((ULONG)DriverBase + 
1459         ImportModuleDirectory->dwRVAFunctionAddressList);
1460
1461       ps("  ImportModuleDirectory->dwRVAFunctionAddressList: 0x%X\n",
1462          ImportModuleDirectory->dwRVAFunctionAddressList);
1463       ps("  ImportAddressList: 0x%X\n", ImportAddressList);
1464
1465       /*  Get the list of functions to import  */
1466       if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1467         {
1468           ps("Using function name list.\n");
1469
1470           FunctionNameList = (PULONG)((ULONG)DriverBase + 
1471             ImportModuleDirectory->dwRVAFunctionNameList);
1472         }
1473       else
1474         {
1475           ps("Using function address list.\n");
1476
1477           FunctionNameList = (PULONG)((ULONG)DriverBase + 
1478             ImportModuleDirectory->dwRVAFunctionAddressList);
1479         }
1480
1481       /* Walk through function list and fixup addresses */
1482       while (*FunctionNameList != 0L)
1483         {
1484           if ((*FunctionNameList) & 0x80000000)
1485             {
1486                /* Hint */
1487               pName = NULL;
1488               Hint = (*FunctionNameList) & 0xffff;
1489             }
1490           else
1491             {
1492               /* Hint name */
1493               pName = (PCHAR)((ULONG)DriverBase + *FunctionNameList + 2);
1494               Hint = *(PWORD)((ULONG)DriverBase + *FunctionNameList);
1495             }
1496           //ps("  Hint:%04x  Name:%s(0x%X)(%x)\n", Hint, pName, pName, ImportAddressList);
1497
1498           *ImportAddressList = LdrSafePEGetExportAddress(ImportModuleBase,
1499                                                          pName,
1500                                                          Hint);
1501
1502           ImportAddressList++;
1503           FunctionNameList++;
1504         }
1505     }
1506
1507   ps("Finished importing.\n");
1508
1509   return(0);
1510 }
1511
1512 #endif /* LIBCAPTIVE */
1513
1514 static PVOID
1515 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
1516                       PCHAR Name,
1517                       USHORT Hint)
1518 {
1519   PIMAGE_EXPORT_DIRECTORY ExportDir;
1520   ULONG ExportDirSize;
1521   USHORT Idx;
1522   PVOID  ExportAddress;
1523   PWORD  OrdinalList;
1524   PDWORD FunctionList, NameList;
1525
1526    ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1527      RtlImageDirectoryEntryToData(ModuleObject->Base,
1528                                   TRUE,
1529                                   IMAGE_DIRECTORY_ENTRY_EXPORT,
1530                                   &ExportDirSize);
1531    DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
1532    if (ExportDir == NULL)
1533      {
1534         return NULL;
1535      }
1536
1537    FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ModuleObject->Base);
1538    NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ModuleObject->Base);
1539    OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ModuleObject->Base);
1540
1541   ExportAddress = 0;
1542
1543   if (Name != NULL)
1544     {
1545       for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1546         {
1547 #if 0
1548           DPRINT("  Name:%s  NameList[%d]:%s\n", 
1549                  Name, 
1550                  Idx, 
1551                  (DWORD) ModuleObject->Base + NameList[Idx]);
1552
1553 #endif
1554           if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
1555             {
1556               ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1557                 FunctionList[OrdinalList[Idx]]);
1558                   if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
1559                       ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
1560                     {
1561                        DPRINT("Forward: %s\n", (PCHAR)ExportAddress);
1562                        ExportAddress = LdrPEFixupForward((PCHAR)ExportAddress);
1563                        DPRINT("ExportAddress: %p\n", ExportAddress);
1564                     }
1565
1566               break;
1567             }
1568         }
1569     }
1570   else  /*  use hint  */
1571     {
1572 #ifndef LIBCAPTIVE
1573       ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1574         FunctionList[Hint - ExportDir->Base]);
1575 #else /* !LIBCAPTIVE */
1576       /* Ordinals not supported by libcaptive */
1577       KeBugCheck(0);
1578 #endif /* !LIBCAPTIVE */
1579     }
1580
1581   if (ExportAddress == NULL)
1582     {
1583       CPRINT("Export not found for %d:%s\n",
1584              Hint,
1585              Name != NULL ? Name : "(Ordinal)");
1586       KeBugCheck(0);
1587     }
1588
1589   return(ExportAddress);
1590 }
1591
1592 #ifndef LIBCAPTIVE
1593
1594 static PVOID
1595 LdrSafePEGetExportAddress(PVOID ImportModuleBase,
1596                           PCHAR Name,
1597                           USHORT Hint)
1598 {
1599   USHORT Idx;
1600   PVOID  ExportAddress;
1601   PWORD  OrdinalList;
1602   PDWORD FunctionList, NameList;
1603   PIMAGE_EXPORT_DIRECTORY  ExportDir;
1604   ULONG ExportDirSize;
1605
1606   static BOOLEAN EP = FALSE;
1607
1608   ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1609     RtlImageDirectoryEntryToData(ImportModuleBase,
1610           TRUE,
1611                 IMAGE_DIRECTORY_ENTRY_EXPORT,
1612                 &ExportDirSize);
1613
1614   if (!EP) {
1615     EP = TRUE;
1616     ps("ExportDir %x\n", ExportDir);
1617   }
1618
1619   FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ImportModuleBase);
1620   NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ImportModuleBase);
1621   OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ImportModuleBase);
1622
1623   ExportAddress = 0;
1624
1625   if (Name != NULL)
1626     {
1627       for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1628         {
1629           if (!strcmp(Name, (PCHAR) ((DWORD)ImportModuleBase + NameList[Idx])))
1630                         {
1631               ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1632                 FunctionList[OrdinalList[Idx]]);
1633               break;
1634             }
1635         }
1636     }
1637   else  /*  use hint  */
1638     {
1639       ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1640
1641         FunctionList[Hint - ExportDir->Base]);
1642     }
1643
1644   if (ExportAddress == 0)
1645     {
1646       ps("Export not found for %d:%s\n",
1647          Hint,
1648          Name != NULL ? Name : "(Ordinal)");
1649       KeBugCheck(0);
1650     }
1651   return ExportAddress;
1652 }
1653
1654 #endif /* LIBCAPTIVE */
1655
1656 static PVOID
1657 LdrPEFixupForward(PCHAR ForwardName)
1658 {
1659    CHAR NameBuffer[128];
1660    UNICODE_STRING ModuleName;
1661    PCHAR p;
1662    PMODULE_OBJECT ModuleObject;
1663
1664    DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
1665
1666    strcpy(NameBuffer, ForwardName);
1667    p = strchr(NameBuffer, '.');
1668    if (p == NULL)
1669      {
1670         return NULL;
1671      }
1672
1673    *p = 0;
1674
1675    DPRINT("Driver: %s  Function: %s\n", NameBuffer, p+1);
1676
1677    RtlCreateUnicodeStringFromAsciiz(&ModuleName,
1678                                     NameBuffer);
1679    ModuleObject = LdrGetModuleObject(&ModuleName);
1680    RtlFreeUnicodeString(&ModuleName);
1681
1682    DPRINT("ModuleObject: %p\n", ModuleObject);
1683
1684    if (ModuleObject == NULL)
1685      {
1686         CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
1687         return NULL;
1688      }
1689
1690   return(LdrPEGetExportAddress(ModuleObject, p+1, 0));
1691 }
1692
1693 /* EOF */