a2276b250d7126b27b6d9d13955f358cee2d928a
[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                                ModuleObject->Base,
554                                ModuleObject->Length);
555   if (!NT_SUCCESS(Status))
556     {
557       IopFreeDeviceNode(DeviceNode);
558       CPRINT("Driver load failed, status (%x)\n", Status);
559     }
560
561   return(Status);
562 }
563
564 #endif /* LIBCAPTIVE */
565
566 NTSTATUS
567 LdrProcessModule(PVOID ModuleLoadBase,
568                  PUNICODE_STRING ModuleName,
569                  PMODULE_OBJECT *ModuleObject)
570 {
571   PIMAGE_DOS_HEADER PEDosHeader;
572
573   /*  If MZ header exists  */
574   PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
575   if (PEDosHeader->e_magic == IMAGE_DOS_MAGIC && PEDosHeader->e_lfanew != 0L)
576     {
577       return LdrPEProcessModule(ModuleLoadBase,
578                                 ModuleName,
579                                 ModuleObject);
580     }
581
582   CPRINT("Module wasn't PE\n");
583   return STATUS_UNSUCCESSFUL;
584 }
585
586
587 PVOID
588 LdrGetExportAddress(PMODULE_OBJECT ModuleObject,
589                     char *Name,
590                     unsigned short Hint)
591 {
592   if (ModuleObject->Flags & MODULE_FLAG_PE)
593     {
594       return LdrPEGetExportAddress(ModuleObject, Name, Hint);
595     }
596   else
597     {
598       return 0;
599     }
600 }
601
602 #ifndef LIBCAPTIVE
603
604 NTSTATUS
605 LdrpQueryModuleInformation(PVOID Buffer,
606                            ULONG Size,
607                            PULONG ReqSize)
608 {
609   PLIST_ENTRY current_entry;
610   PMODULE_OBJECT current;
611   ULONG ModuleCount = 0;
612   PSYSTEM_MODULE_INFORMATION Smi;
613   ANSI_STRING AnsiName;
614   PCHAR p;
615   KIRQL Irql;
616
617   KeAcquireSpinLock(&ModuleListLock,&Irql);
618
619   /* calculate required size */
620   current_entry = ModuleListHead.Flink;
621   while (current_entry != (&ModuleListHead))
622     {
623       ModuleCount++;
624       current_entry = current_entry->Flink;
625     }
626
627   *ReqSize = sizeof(SYSTEM_MODULE_INFORMATION)+
628     (ModuleCount - 1) * sizeof(SYSTEM_MODULE_INFORMATION_ENTRY);
629
630   if (Size < *ReqSize)
631     {
632       KeReleaseSpinLock(&ModuleListLock, Irql);
633       return(STATUS_INFO_LENGTH_MISMATCH);
634     }
635
636   /* fill the buffer */
637   memset(Buffer, '=', Size);
638
639   Smi = (PSYSTEM_MODULE_INFORMATION)Buffer;
640   Smi->Count = ModuleCount;
641
642   ModuleCount = 0;
643   current_entry = ModuleListHead.Flink;
644   while (current_entry != (&ModuleListHead))
645     {
646       current = CONTAINING_RECORD(current_entry,MODULE_OBJECT,ListEntry);
647
648       Smi->Module[ModuleCount].Unknown1 = 0;            /* Always 0 */
649       Smi->Module[ModuleCount].Unknown2 = 0;            /* Always 0 */
650       Smi->Module[ModuleCount].Base = current->Base;
651       Smi->Module[ModuleCount].Size = current->Length;
652       Smi->Module[ModuleCount].Flags = 0;               /* Flags ??? (GN) */
653       Smi->Module[ModuleCount].Index = ModuleCount;
654       Smi->Module[ModuleCount].NameLength = 0;
655       Smi->Module[ModuleCount].LoadCount = 0; /* FIXME */
656
657       AnsiName.Length = 0;
658       AnsiName.MaximumLength = 256;
659       AnsiName.Buffer = Smi->Module[ModuleCount].ImageName;
660       RtlUnicodeStringToAnsiString(&AnsiName,
661                                    &current->FullName,
662                                    FALSE);
663
664       p = strrchr(AnsiName.Buffer, '\\');
665       if (p == NULL)
666         {
667           Smi->Module[ModuleCount].PathLength = 0;
668         }
669       else
670         {
671           p++;
672           Smi->Module[ModuleCount].PathLength = p - AnsiName.Buffer;
673         }
674
675       ModuleCount++;
676       current_entry = current_entry->Flink;
677     }
678
679   KeReleaseSpinLock(&ModuleListLock, Irql);
680
681   return(STATUS_SUCCESS);
682 }
683
684 #endif /* LIBCAPTIVE */
685
686 #ifndef LIBCAPTIVE
687 static
688 #endif /* LIBCAPTIVE */
689 VOID
690 LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,
691                         PUNICODE_STRING FullName)
692 {
693    UNICODE_STRING Name;
694    PWCHAR p;
695    PWCHAR q;
696
697    DPRINT("LdrpBuildModuleBaseName()\n");
698    DPRINT("FullName %wZ\n", FullName);
699
700    p = wcsrchr(FullName->Buffer, L'\\');
701    if (p == NULL)
702      {
703         p = FullName->Buffer;
704      }
705    else
706      {
707         p++;
708      }
709
710    DPRINT("p %S\n", p);
711
712    RtlCreateUnicodeString(&Name, p);
713
714    q = wcschr(Name.Buffer, L'.');
715    if (q != NULL)
716      {
717         *q = (WCHAR)0;
718      }
719
720    DPRINT("p %S\n", p);
721
722    RtlCreateUnicodeString(BaseName, Name.Buffer);
723    RtlFreeUnicodeString(&Name);
724 }
725
726
727 static LONG
728 LdrpCompareModuleNames(IN PUNICODE_STRING String1,
729                        IN PUNICODE_STRING String2)
730 {
731   ULONG len1, len2, i;
732   PWCHAR s1, s2, p;
733   WCHAR  c1, c2;
734
735   if (String1 && String2)
736     {
737       /* Search String1 for last path component */
738       len1 = String1->Length / sizeof(WCHAR);
739       s1 = String1->Buffer;
740       for (i = 0, p = String1->Buffer; i < String1->Length; i = i + sizeof(WCHAR), p++)
741         {
742           if (*p == L'\\')
743             {
744               if (i == String1->Length - sizeof(WCHAR))
745                 {
746                   s1 = NULL;
747                   len1 = 0;
748                 }
749               else
750                 {
751                   s1 = p + 1;
752                   len1 = (String1->Length - i) / sizeof(WCHAR);
753                 }
754             }
755         }
756
757       /* Search String2 for last path component */
758       len2 = String2->Length / sizeof(WCHAR);
759       s2 = String2->Buffer;
760       for (i = 0, p = String2->Buffer; i < String2->Length; i = i + sizeof(WCHAR), p++)
761         {
762           if (*p == L'\\')
763             {
764               if (i == String2->Length - sizeof(WCHAR))
765                 {
766                   s2 = NULL;
767                   len2 = 0;
768                 }
769               else
770                 {
771                   s2 = p + 1;
772                   len2 = (String2->Length - i) / sizeof(WCHAR);
773                 }
774             }
775         }
776
777       /* Compare last path components */
778       if (s1 && s2)
779         {
780           while (1)
781             {
782               c1 = len1-- ? RtlUpcaseUnicodeChar (*s1++) : 0;
783               c2 = len2-- ? RtlUpcaseUnicodeChar (*s2++) : 0;
784               if ((c1 == 0 && c2 == L'.') || (c1 == L'.' && c2 == 0))
785                 return(0);
786               if (!c1 || !c2 || c1 != c2)
787                 return(c1 - c2);
788             }
789         }
790     }
791
792   return(0);
793 }
794
795
796 PMODULE_OBJECT
797 LdrGetModuleObject(PUNICODE_STRING ModuleName)
798 {
799   PMODULE_OBJECT Module;
800   PLIST_ENTRY Entry;
801   KIRQL Irql;
802
803   DPRINT("LdrpGetModuleObject(%wZ) called\n", ModuleName);
804
805   KeAcquireSpinLock(&ModuleListLock,&Irql);
806
807   Entry = ModuleListHead.Flink;
808   while (Entry != &ModuleListHead)
809     {
810       Module = CONTAINING_RECORD(Entry, MODULE_OBJECT, ListEntry);
811
812       DPRINT("Comparing %wZ and %wZ\n",
813              &Module->BaseName,
814              ModuleName);
815
816       if (!LdrpCompareModuleNames(&Module->BaseName, ModuleName))
817         {
818           DPRINT("Module %wZ\n", &Module->BaseName);
819           KeReleaseSpinLock(&ModuleListLock, Irql);
820           return(Module);
821         }
822
823       Entry = Entry->Flink;
824     }
825
826   KeReleaseSpinLock(&ModuleListLock, Irql);
827
828   DPRINT("Could not find module '%wZ'\n", ModuleName);
829
830   return(NULL);
831 }
832
833
834 /*  ----------------------------------------------  PE Module support */
835
836 static BOOL
837 PageNeedsWriteAccess(PVOID PageStart,
838                      PVOID DriverBase,
839                      PIMAGE_FILE_HEADER PEFileHeader,
840                      PIMAGE_SECTION_HEADER PESectionHeaders)
841 {
842   BOOL NeedsWriteAccess;
843   unsigned Idx;
844   ULONG Characteristics;
845   ULONG Length;
846   PVOID BaseAddress;
847
848   NeedsWriteAccess = FALSE;
849   /* Set the protections for the various parts of the driver */
850   for (Idx = 0; Idx < PEFileHeader->NumberOfSections && ! NeedsWriteAccess; Idx++)
851     {
852       Characteristics = PESectionHeaders[Idx].Characteristics;
853       if (!(Characteristics & IMAGE_SECTION_CHAR_CODE) ||
854           (Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
855            Characteristics & IMAGE_SECTION_CHAR_DATA ||
856            Characteristics & IMAGE_SECTION_CHAR_BSS))
857         {
858           Length = 
859               max(PESectionHeaders[Idx].Misc.VirtualSize,
860                   PESectionHeaders[Idx].SizeOfRawData);
861           BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
862           NeedsWriteAccess = BaseAddress < PageStart + PAGE_SIZE &&
863                              PageStart < (PVOID)((PCHAR) BaseAddress + Length);
864         }
865     }
866
867   return(NeedsWriteAccess);
868 }
869
870 static NTSTATUS
871 LdrPEProcessModule(PVOID ModuleLoadBase,
872                    PUNICODE_STRING FileName,
873                    PMODULE_OBJECT *ModuleObject)
874 {
875   unsigned int DriverSize, Idx;
876   ULONG RelocDelta, NumRelocs;
877   DWORD CurrentSize, TotalRelocs;
878   PVOID DriverBase;
879   PULONG PEMagic;
880   PIMAGE_DOS_HEADER PEDosHeader;
881   PIMAGE_FILE_HEADER PEFileHeader;
882   PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
883   PIMAGE_SECTION_HEADER PESectionHeaders;
884   PRELOCATION_DIRECTORY RelocDir;
885   PRELOCATION_ENTRY RelocEntry;
886   PMODULE_OBJECT  LibraryModuleObject;
887   PMODULE_OBJECT CreatedModuleObject;
888   PVOID *ImportAddressList;
889   PULONG FunctionNameList;
890   PCHAR pName;
891   WORD Hint;
892   UNICODE_STRING ModuleName;
893   UNICODE_STRING NameString;
894   WCHAR  NameBuffer[60];
895   MODULE_TEXT_SECTION* ModuleTextSection;
896   NTSTATUS Status;
897   KIRQL Irql;
898
899   DPRINT("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
900
901   /*  Get header pointers  */
902   PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
903   PEMagic = (PULONG) ((unsigned int) ModuleLoadBase + 
904     PEDosHeader->e_lfanew);
905   PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase + 
906     PEDosHeader->e_lfanew + sizeof(ULONG));
907   PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase + 
908     PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
909   PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase + 
910     PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
911     sizeof(IMAGE_OPTIONAL_HEADER));
912   CHECKPOINT;
913
914   /*  Check file magic numbers  */
915   if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
916     {
917       CPRINT("Incorrect MZ magic: %04x\n", PEDosHeader->e_magic);
918       return STATUS_UNSUCCESSFUL;
919     }
920   if (PEDosHeader->e_lfanew == 0)
921     {
922       CPRINT("Invalid lfanew offset: %08x\n", PEDosHeader->e_lfanew);
923       return STATUS_UNSUCCESSFUL;
924     }
925   if (*PEMagic != IMAGE_PE_MAGIC)
926     {
927       CPRINT("Incorrect PE magic: %08x\n", *PEMagic);
928       return STATUS_UNSUCCESSFUL;
929     }
930   if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
931     {
932       CPRINT("Incorrect Architechture: %04x\n", PEFileHeader->Machine);
933       return STATUS_UNSUCCESSFUL;
934     }
935   CHECKPOINT;
936
937   /* FIXME: if image is fixed-address load, then fail  */
938
939   /* FIXME: check/verify OS version number  */
940
941   DPRINT("OptionalHdrMagic:%04x LinkVersion:%d.%d\n", 
942          PEOptionalHeader->Magic,
943          PEOptionalHeader->MajorLinkerVersion,
944          PEOptionalHeader->MinorLinkerVersion);
945   DPRINT("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
946   CHECKPOINT;
947
948   /*  Determine the size of the module  */
949   DriverSize = PEOptionalHeader->SizeOfImage;
950   DPRINT("DriverSize %x\n",DriverSize);
951
952   /*  Allocate a virtual section for the module  */
953   DriverBase = MmAllocateSection(DriverSize);
954   if (DriverBase == 0)
955     {
956       CPRINT("Failed to allocate a virtual section for driver\n");
957       return STATUS_UNSUCCESSFUL;
958     }
959   DbgPrint("DriverBase for %wZ: %x\n", FileName, DriverBase);
960   CHECKPOINT;
961   /*  Copy headers over */
962   memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
963    CurrentSize = 0;
964   /*  Copy image sections into virtual section  */
965   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
966     {
967       //  Copy current section into current offset of virtual section
968       if (PESectionHeaders[Idx].Characteristics & 
969           (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
970         {
971            DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
972                   PESectionHeaders[Idx].VirtualAddress + DriverBase);
973            memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
974                   (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
975                   PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData
976                   ? PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
977         }
978       else
979         {
980            DPRINT("PESectionHeaders[Idx].VirtualAddress + DriverBase %x\n",
981                   PESectionHeaders[Idx].VirtualAddress + DriverBase);
982            memset(PESectionHeaders[Idx].VirtualAddress + DriverBase, 
983                   '\0', PESectionHeaders[Idx].Misc.VirtualSize);
984
985         }
986       CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
987                               PEOptionalHeader->SectionAlignment);
988
989
990 //      CurrentBase = (PVOID)((DWORD)CurrentBase + 
991   //      ROUND_UP(PESectionHeaders[Idx].SizeOfRawData.Misc.VirtualSize,
992     //             PEOptionalHeader->SectionAlignment));
993     }
994
995   /*  Perform relocation fixups  */
996   RelocDelta = (DWORD) DriverBase - PEOptionalHeader->ImageBase;
997   RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
998     IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
999   DPRINT("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n", 
1000          DriverBase,
1001          PEOptionalHeader->ImageBase,
1002          RelocDelta);   
1003   DPRINT("RelocDir %x\n",RelocDir);
1004 #if 1
1005   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1006     {
1007        if (PESectionHeaders[Idx].VirtualAddress == (DWORD)RelocDir)
1008          {
1009             DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
1010                    PESectionHeaders[Idx].Name,
1011                    PESectionHeaders[Idx].PointerToRawData);
1012             RelocDir = PESectionHeaders[Idx].PointerToRawData +
1013               ModuleLoadBase;
1014             CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
1015             break;
1016          }
1017     }
1018 #else
1019    RelocDir = RelocDir + (ULONG)DriverBase;
1020    CurrentSize = PEOptionalHeader->DataDirectory
1021                   [IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
1022 #endif
1023   DPRINT("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1024   TotalRelocs = 0;
1025   while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1026     {
1027       NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) / 
1028         sizeof(WORD);
1029 /*      DPRINT("RelocDir at %08lx for VA %08lx with %08lx relocs\n",
1030              RelocDir, 
1031              RelocDir->VirtualAddress,
1032              NumRelocs);*/
1033       RelocEntry = (PRELOCATION_ENTRY) ((DWORD)RelocDir + 
1034         sizeof(RELOCATION_DIRECTORY));
1035       for (Idx = 0; Idx < NumRelocs; Idx++)
1036         {
1037            ULONG Offset;
1038            ULONG Type;
1039            PDWORD RelocItem;
1040            
1041            Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1042            Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1043            RelocItem = (PDWORD)(DriverBase + RelocDir->VirtualAddress + 
1044                                 Offset);
1045 /*         DPRINT("  reloc at %08lx %x %s old:%08lx new:%08lx\n", 
1046                   RelocItem,
1047                   Type,
1048                   Type ? "HIGHLOW" : "ABS",
1049                   *RelocItem,
1050                   (*RelocItem) + RelocDelta); */
1051           if (Type == 3)
1052             {
1053               (*RelocItem) += RelocDelta;
1054             }
1055           else if (Type != 0)
1056             {
1057               CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1058               return STATUS_UNSUCCESSFUL;
1059             }
1060         }
1061       TotalRelocs += RelocDir->SizeOfBlock;
1062       RelocDir = (PRELOCATION_DIRECTORY)((DWORD)RelocDir + 
1063         RelocDir->SizeOfBlock);
1064 //      DPRINT("TotalRelocs: %08lx  CurrentSize: %08lx\n", TotalRelocs, CurrentSize);
1065     }
1066    
1067   DPRINT("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1068          PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1069          .VirtualAddress);
1070   /*  Perform import fixups  */
1071   if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1072     {
1073       PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1074
1075       /*  Process each import module  */
1076       ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1077         ((DWORD)DriverBase + PEOptionalHeader->
1078           DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1079       DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
1080       while (ImportModuleDirectory->dwRVAModuleName)
1081         {
1082           /*  Check to make sure that import lib is kernel  */
1083           pName = (PCHAR) DriverBase + 
1084             ImportModuleDirectory->dwRVAModuleName;
1085
1086           RtlCreateUnicodeStringFromAsciiz(&ModuleName, pName);
1087           DPRINT("Import module: %wZ\n", &ModuleName);
1088
1089           LibraryModuleObject = LdrGetModuleObject(&ModuleName);
1090           if (LibraryModuleObject == NULL)
1091             {
1092               DPRINT("Module '%wZ' not loaded yet\n", &ModuleName);
1093               wcscpy(NameBuffer, REACTOS_UCS2(L"\\SystemRoot\\system32\\drivers\\"));
1094               wcscat(NameBuffer, ModuleName.Buffer);
1095               RtlInitUnicodeString(&NameString, NameBuffer);
1096               Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1097               if (!NT_SUCCESS(Status))
1098                 {
1099                   wcscpy(NameBuffer, REACTOS_UCS2(L"\\SystemRoot\\system32\\"));
1100                   wcscat(NameBuffer, ModuleName.Buffer);
1101                   RtlInitUnicodeString(&NameString, NameBuffer);
1102                   Status = LdrLoadModule(&NameString, &LibraryModuleObject);
1103                   if (!NT_SUCCESS(Status))
1104                     {
1105                       DPRINT1("Unknown import module: %wZ (Status %lx)\n", &ModuleName, Status);
1106                       return(Status);
1107                     }
1108                 }
1109             }
1110           /*  Get the import address list  */
1111           ImportAddressList = (PVOID *) ((DWORD)DriverBase + 
1112             ImportModuleDirectory->dwRVAFunctionAddressList);
1113
1114           /*  Get the list of functions to import  */
1115           if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1116             {
1117               FunctionNameList = (PULONG) ((DWORD)DriverBase + 
1118                 ImportModuleDirectory->dwRVAFunctionNameList);
1119             }
1120           else
1121             {
1122               FunctionNameList = (PULONG) ((DWORD)DriverBase + 
1123                 ImportModuleDirectory->dwRVAFunctionAddressList);
1124             }
1125           /*  Walk through function list and fixup addresses  */
1126           while (*FunctionNameList != 0L)
1127             {
1128               if ((*FunctionNameList) & 0x80000000) // hint
1129                 {
1130                   pName = NULL;
1131
1132
1133                   Hint = (*FunctionNameList) & 0xffff;
1134                 }
1135               else // hint-name
1136                 {
1137                   pName = (PCHAR)((DWORD)DriverBase + 
1138                                   *FunctionNameList + 2);
1139                   Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
1140                 }
1141               DPRINT("  Hint:%04x  Name:%s\n", Hint, pName);
1142
1143               /*  Fixup the current import symbol  */
1144               if (LibraryModuleObject != NULL)
1145                 {
1146                   *ImportAddressList = LdrGetExportAddress(LibraryModuleObject, 
1147                                                            pName, 
1148                                                            Hint);
1149                 }
1150               else
1151                 {
1152                   CPRINT("Unresolved kernel symbol: %s\n", pName);
1153                   return STATUS_UNSUCCESSFUL;
1154                 }
1155               ImportAddressList++;
1156               FunctionNameList++;
1157             }
1158
1159           RtlFreeUnicodeString(&ModuleName);
1160
1161           ImportModuleDirectory++;
1162         }
1163     }
1164
1165   /* Set the protections for the various parts of the driver */
1166   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1167     {
1168       ULONG Characteristics = PESectionHeaders[Idx].Characteristics;
1169       ULONG Length;
1170       PVOID BaseAddress;
1171       PVOID PageAddress;
1172       if (Characteristics & IMAGE_SECTION_CHAR_CODE &&
1173           !(Characteristics & IMAGE_SECTION_CHAR_WRITABLE ||
1174             Characteristics & IMAGE_SECTION_CHAR_DATA ||
1175             Characteristics & IMAGE_SECTION_CHAR_BSS))
1176         {
1177           Length = 
1178               max(PESectionHeaders[Idx].Misc.VirtualSize,
1179                   PESectionHeaders[Idx].SizeOfRawData);
1180           BaseAddress = PESectionHeaders[Idx].VirtualAddress + DriverBase;
1181           PageAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
1182           if (! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1183             {
1184               MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1185             }
1186           PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1187           while ((PVOID)((PCHAR) PageAddress + PAGE_SIZE) <
1188                  (PVOID)((PCHAR) BaseAddress + Length))
1189             {
1190               MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1191               PageAddress = (PVOID)((PCHAR) PageAddress + PAGE_SIZE);
1192             }
1193           if (PageAddress < (PVOID)((PCHAR) BaseAddress + Length) &&
1194               ! PageNeedsWriteAccess(PageAddress, DriverBase, PEFileHeader, PESectionHeaders))
1195             {
1196               MmSetPageProtect(NULL, PageAddress, PAGE_READONLY);
1197             }
1198         }
1199     }
1200
1201   /* Create the module */
1202   CreatedModuleObject = ExAllocatePool(NonPagedPool, sizeof(MODULE_OBJECT));
1203   if (CreatedModuleObject == NULL)
1204     {
1205       return(STATUS_INSUFFICIENT_RESOURCES);
1206     }
1207
1208   RtlZeroMemory(CreatedModuleObject, sizeof(MODULE_OBJECT));
1209
1210    /*  Initialize ModuleObject data  */
1211   CreatedModuleObject->Base = DriverBase;
1212   CreatedModuleObject->Flags = MODULE_FLAG_PE;
1213   
1214   RtlCreateUnicodeString(&CreatedModuleObject->FullName,
1215                          FileName->Buffer);
1216   LdrpBuildModuleBaseName(&CreatedModuleObject->BaseName,
1217                           &CreatedModuleObject->FullName);
1218   
1219   CreatedModuleObject->EntryPoint = 
1220     (PVOID)((DWORD)DriverBase + 
1221             PEOptionalHeader->AddressOfEntryPoint);
1222   CreatedModuleObject->Length = DriverSize;
1223   DPRINT("EntryPoint at %x\n", CreatedModuleObject->EntryPoint);
1224   
1225   CreatedModuleObject->Image.PE.FileHeader =
1226     (PIMAGE_FILE_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG));
1227
1228   DPRINT("FileHeader at %x\n", CreatedModuleObject->Image.PE.FileHeader);
1229   CreatedModuleObject->Image.PE.OptionalHeader = 
1230     (PIMAGE_OPTIONAL_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1231     sizeof(IMAGE_FILE_HEADER));
1232   DPRINT("OptionalHeader at %x\n", CreatedModuleObject->Image.PE.OptionalHeader);
1233   CreatedModuleObject->Image.PE.SectionList = 
1234     (PIMAGE_SECTION_HEADER) ((unsigned int) DriverBase + PEDosHeader->e_lfanew + sizeof(ULONG) +
1235     sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER));
1236   DPRINT("SectionList at %x\n", CreatedModuleObject->Image.PE.SectionList);
1237
1238   /* Insert module */
1239   KeAcquireSpinLock(&ModuleListLock, &Irql);
1240   InsertTailList(&ModuleListHead,
1241                  &CreatedModuleObject->ListEntry);
1242   KeReleaseSpinLock(&ModuleListLock, Irql);
1243
1244
1245   ModuleTextSection = ExAllocatePool(NonPagedPool, 
1246                                      sizeof(MODULE_TEXT_SECTION));
1247   assert(ModuleTextSection);
1248   RtlZeroMemory(ModuleTextSection, sizeof(MODULE_TEXT_SECTION));
1249   ModuleTextSection->Base = (ULONG)DriverBase;
1250   ModuleTextSection->Length = DriverSize;
1251   ModuleTextSection->Name = ExAllocatePool(NonPagedPool, 
1252         (wcslen(CreatedModuleObject->BaseName.Buffer) + 1) * sizeof(WCHAR));
1253   wcscpy(ModuleTextSection->Name, CreatedModuleObject->BaseName.Buffer);
1254   ModuleTextSection->OptionalHeader = 
1255     CreatedModuleObject->Image.PE.OptionalHeader;
1256   InsertTailList(&ModuleTextListHead, &ModuleTextSection->ListEntry);
1257
1258   CreatedModuleObject->TextSection = ModuleTextSection;
1259
1260   *ModuleObject = CreatedModuleObject;
1261
1262   DPRINT("Loading Module %wZ...\n", FileName);
1263
1264   if ((KdDebuggerEnabled == TRUE) && (KdDebugState & KD_DEBUG_GDB))
1265     {
1266       DPRINT("Module %wZ loaded at 0x%.08x.\n",
1267               FileName, CreatedModuleObject->Base);
1268     }
1269
1270   return STATUS_SUCCESS;
1271 }
1272
1273 #ifndef LIBCAPTIVE
1274
1275 PVOID
1276 LdrSafePEProcessModule(PVOID ModuleLoadBase,
1277                        PVOID DriverBase,
1278                        PVOID ImportModuleBase,
1279                        PULONG DriverSize)
1280 {
1281   unsigned int Idx;
1282   ULONG RelocDelta, NumRelocs;
1283   ULONG CurrentSize, TotalRelocs;
1284   PULONG PEMagic;
1285   PIMAGE_DOS_HEADER PEDosHeader;
1286   PIMAGE_FILE_HEADER PEFileHeader;
1287   PIMAGE_OPTIONAL_HEADER PEOptionalHeader;
1288   PIMAGE_SECTION_HEADER PESectionHeaders;
1289   PRELOCATION_DIRECTORY RelocDir;
1290   PRELOCATION_ENTRY RelocEntry;
1291   PVOID *ImportAddressList;
1292   PULONG FunctionNameList;
1293   PCHAR pName;
1294   USHORT Hint;
1295
1296   ps("Processing PE Module at module base:%08lx\n", ModuleLoadBase);
1297
1298   /*  Get header pointers  */
1299   PEDosHeader = (PIMAGE_DOS_HEADER) ModuleLoadBase;
1300   PEMagic = (PULONG) ((unsigned int) ModuleLoadBase + 
1301     PEDosHeader->e_lfanew);
1302   PEFileHeader = (PIMAGE_FILE_HEADER) ((unsigned int) ModuleLoadBase + 
1303     PEDosHeader->e_lfanew + sizeof(ULONG));
1304   PEOptionalHeader = (PIMAGE_OPTIONAL_HEADER) ((unsigned int) ModuleLoadBase + 
1305     PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER));
1306   PESectionHeaders = (PIMAGE_SECTION_HEADER) ((unsigned int) ModuleLoadBase + 
1307     PEDosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
1308     sizeof(IMAGE_OPTIONAL_HEADER));
1309   CHECKPOINT;
1310
1311   /*  Check file magic numbers  */
1312   if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC)
1313     {
1314       return 0;
1315     }
1316   if (PEDosHeader->e_lfanew == 0)
1317     {
1318       return 0;
1319     }
1320   if (*PEMagic != IMAGE_PE_MAGIC)
1321     {
1322       return 0;
1323     }
1324   if (PEFileHeader->Machine != IMAGE_FILE_MACHINE_I386)
1325     {
1326       return 0;
1327     }
1328
1329   ps("OptionalHdrMagic:%04x LinkVersion:%d.%d\n", 
1330          PEOptionalHeader->Magic,
1331          PEOptionalHeader->MajorLinkerVersion,
1332          PEOptionalHeader->MinorLinkerVersion);
1333   ps("Entry Point:%08lx\n", PEOptionalHeader->AddressOfEntryPoint);
1334
1335   /*  Determine the size of the module  */
1336   *DriverSize = PEOptionalHeader->SizeOfImage;
1337   ps("DriverSize %x\n",*DriverSize);
1338
1339   /*  Copy headers over */
1340   if (DriverBase != ModuleLoadBase)
1341     {
1342       memcpy(DriverBase, ModuleLoadBase, PEOptionalHeader->SizeOfHeaders);
1343     }
1344
1345   ps("Hdr: 0x%X\n", (ULONG)PEOptionalHeader);
1346   ps("Hdr->SizeOfHeaders: 0x%X\n", (ULONG)PEOptionalHeader->SizeOfHeaders);
1347   ps("FileHdr->NumberOfSections: 0x%X\n", (ULONG)PEFileHeader->NumberOfSections);
1348
1349   /* Ntoskrnl.exe need no relocation fixups since it is linked to run at the same
1350      address as it is mapped */
1351   if (DriverBase != ModuleLoadBase)
1352     {
1353       CurrentSize = 0;
1354
1355   /*  Copy image sections into virtual section  */
1356   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1357     {
1358       //  Copy current section into current offset of virtual section
1359       if (PESectionHeaders[Idx].Characteristics & 
1360           (IMAGE_SECTION_CHAR_CODE | IMAGE_SECTION_CHAR_DATA))
1361         {
1362           //ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1363           //PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1364           memcpy(PESectionHeaders[Idx].VirtualAddress + DriverBase,
1365                  (PVOID)(ModuleLoadBase + PESectionHeaders[Idx].PointerToRawData),
1366                  PESectionHeaders[Idx].Misc.VirtualSize > PESectionHeaders[Idx].SizeOfRawData ?
1367                    PESectionHeaders[Idx].SizeOfRawData : PESectionHeaders[Idx].Misc.VirtualSize );
1368         }
1369       else
1370         {
1371           ps("PESectionHeaders[Idx].VirtualAddress (%X) + DriverBase %x\n",
1372              PESectionHeaders[Idx].VirtualAddress, PESectionHeaders[Idx].VirtualAddress + DriverBase);
1373           memset(PESectionHeaders[Idx].VirtualAddress + DriverBase, 
1374                  '\0',
1375                  PESectionHeaders[Idx].Misc.VirtualSize);
1376         }
1377       CurrentSize += ROUND_UP(PESectionHeaders[Idx].Misc.VirtualSize,
1378                               PEOptionalHeader->SectionAlignment);
1379     }
1380
1381   /*  Perform relocation fixups  */
1382   RelocDelta = (ULONG) DriverBase - PEOptionalHeader->ImageBase;
1383   RelocDir = (PRELOCATION_DIRECTORY)(PEOptionalHeader->DataDirectory[
1384     IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
1385   ps("DrvrBase:%08lx ImgBase:%08lx RelocDelta:%08lx\n", 
1386          DriverBase,
1387          PEOptionalHeader->ImageBase,
1388          RelocDelta);   
1389   ps("RelocDir %x\n",RelocDir);
1390
1391   for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
1392     {
1393       if (PESectionHeaders[Idx].VirtualAddress == (ULONG)RelocDir)
1394         {
1395           DPRINT("Name %.8s PESectionHeader[Idx].PointerToRawData %x\n",
1396                  PESectionHeaders[Idx].Name,
1397                  PESectionHeaders[Idx].PointerToRawData);
1398           RelocDir = PESectionHeaders[Idx].PointerToRawData + ModuleLoadBase;
1399           CurrentSize = PESectionHeaders[Idx].Misc.VirtualSize;
1400           break;
1401         }
1402     }
1403
1404   ps("RelocDir %08lx CurrentSize %08lx\n", RelocDir, CurrentSize);
1405
1406   TotalRelocs = 0;
1407   while (TotalRelocs < CurrentSize && RelocDir->SizeOfBlock != 0)
1408     {
1409       NumRelocs = (RelocDir->SizeOfBlock - sizeof(RELOCATION_DIRECTORY)) / 
1410         sizeof(USHORT);
1411       RelocEntry = (PRELOCATION_ENTRY)((ULONG)RelocDir + 
1412         sizeof(RELOCATION_DIRECTORY));
1413       for (Idx = 0; Idx < NumRelocs; Idx++)
1414         {
1415           ULONG Offset;
1416           ULONG Type;
1417           PULONG RelocItem;
1418
1419           Offset = RelocEntry[Idx].TypeOffset & 0xfff;
1420           Type = (RelocEntry[Idx].TypeOffset >> 12) & 0xf;
1421           RelocItem = (PULONG)(DriverBase + RelocDir->VirtualAddress + Offset);
1422           if (Type == 3)
1423             {
1424               (*RelocItem) += RelocDelta;
1425             }
1426           else if (Type != 0)
1427             {
1428               CPRINT("Unknown relocation type %x at %x\n",Type, &Type);
1429               return(0);
1430             }
1431         }
1432       TotalRelocs += RelocDir->SizeOfBlock;
1433       RelocDir = (PRELOCATION_DIRECTORY)((ULONG)RelocDir + 
1434         RelocDir->SizeOfBlock);
1435     }
1436
1437     ps("PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] %x\n",
1438          PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1439          .VirtualAddress);
1440   }
1441
1442   /*  Perform import fixups  */
1443   if (PEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1444     {
1445       PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
1446
1447       /*  Process each import module  */
1448       ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
1449         ((ULONG)DriverBase + PEOptionalHeader->
1450           DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
1451
1452       ps("Processeing import directory at %p\n", ImportModuleDirectory);
1453
1454       /*  Check to make sure that import lib is kernel  */
1455       pName = (PCHAR)DriverBase + ImportModuleDirectory->dwRVAModuleName;
1456
1457       ps("Import module: %s\n", pName);
1458
1459       /*  Get the import address list  */
1460       ImportAddressList = (PVOID *)((ULONG)DriverBase + 
1461         ImportModuleDirectory->dwRVAFunctionAddressList);
1462
1463       ps("  ImportModuleDirectory->dwRVAFunctionAddressList: 0x%X\n",
1464          ImportModuleDirectory->dwRVAFunctionAddressList);
1465       ps("  ImportAddressList: 0x%X\n", ImportAddressList);
1466
1467       /*  Get the list of functions to import  */
1468       if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1469         {
1470           ps("Using function name list.\n");
1471
1472           FunctionNameList = (PULONG)((ULONG)DriverBase + 
1473             ImportModuleDirectory->dwRVAFunctionNameList);
1474         }
1475       else
1476         {
1477           ps("Using function address list.\n");
1478
1479           FunctionNameList = (PULONG)((ULONG)DriverBase + 
1480             ImportModuleDirectory->dwRVAFunctionAddressList);
1481         }
1482
1483       /* Walk through function list and fixup addresses */
1484       while (*FunctionNameList != 0L)
1485         {
1486           if ((*FunctionNameList) & 0x80000000)
1487             {
1488                /* Hint */
1489               pName = NULL;
1490               Hint = (*FunctionNameList) & 0xffff;
1491             }
1492           else
1493             {
1494               /* Hint name */
1495               pName = (PCHAR)((ULONG)DriverBase + *FunctionNameList + 2);
1496               Hint = *(PWORD)((ULONG)DriverBase + *FunctionNameList);
1497             }
1498           //ps("  Hint:%04x  Name:%s(0x%X)(%x)\n", Hint, pName, pName, ImportAddressList);
1499
1500           *ImportAddressList = LdrSafePEGetExportAddress(ImportModuleBase,
1501                                                          pName,
1502                                                          Hint);
1503
1504           ImportAddressList++;
1505           FunctionNameList++;
1506         }
1507     }
1508
1509   ps("Finished importing.\n");
1510
1511   return(0);
1512 }
1513
1514 #endif /* LIBCAPTIVE */
1515
1516 static PVOID
1517 LdrPEGetExportAddress(PMODULE_OBJECT ModuleObject,
1518                       PCHAR Name,
1519                       USHORT Hint)
1520 {
1521   PIMAGE_EXPORT_DIRECTORY ExportDir;
1522   ULONG ExportDirSize;
1523   USHORT Idx;
1524   PVOID  ExportAddress;
1525   PWORD  OrdinalList;
1526   PDWORD FunctionList, NameList;
1527
1528    ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1529      RtlImageDirectoryEntryToData(ModuleObject->Base,
1530                                   TRUE,
1531                                   IMAGE_DIRECTORY_ENTRY_EXPORT,
1532                                   &ExportDirSize);
1533    DPRINT("ExportDir %p ExportDirSize %lx\n", ExportDir, ExportDirSize);
1534    if (ExportDir == NULL)
1535      {
1536         return NULL;
1537      }
1538
1539    FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ModuleObject->Base);
1540    NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ModuleObject->Base);
1541    OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ModuleObject->Base);
1542
1543   ExportAddress = 0;
1544
1545   if (Name != NULL)
1546     {
1547       for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1548         {
1549 #if 0
1550           DPRINT("  Name:%s  NameList[%d]:%s\n", 
1551                  Name, 
1552                  Idx, 
1553                  (DWORD) ModuleObject->Base + NameList[Idx]);
1554
1555 #endif
1556           if (!strcmp(Name, (PCHAR) ((DWORD)ModuleObject->Base + NameList[Idx])))
1557             {
1558               ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1559                 FunctionList[OrdinalList[Idx]]);
1560                   if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
1561                       ((ULONG)ExportAddress < (ULONG)ExportDir + ExportDirSize))
1562                     {
1563                        DPRINT("Forward: %s\n", (PCHAR)ExportAddress);
1564                        ExportAddress = LdrPEFixupForward((PCHAR)ExportAddress);
1565                        DPRINT("ExportAddress: %p\n", ExportAddress);
1566                     }
1567
1568               break;
1569             }
1570         }
1571     }
1572   else  /*  use hint  */
1573     {
1574 #ifndef LIBCAPTIVE
1575       ExportAddress = (PVOID) ((DWORD)ModuleObject->Base +
1576         FunctionList[Hint - ExportDir->Base]);
1577 #else /* !LIBCAPTIVE */
1578       /* Ordinals not supported by libcaptive */
1579       KeBugCheck(0);
1580 #endif /* !LIBCAPTIVE */
1581     }
1582
1583   if (ExportAddress == NULL)
1584     {
1585       DbgPrint("Export not found for %d:%s\n",
1586              Hint,
1587              Name != NULL ? Name : "(Ordinal)");
1588       KEBUGCHECK(0);
1589     }
1590
1591   return(ExportAddress);
1592 }
1593
1594 #ifndef LIBCAPTIVE
1595
1596 static PVOID
1597 LdrSafePEGetExportAddress(PVOID ImportModuleBase,
1598                           PCHAR Name,
1599                           USHORT Hint)
1600 {
1601   USHORT Idx;
1602   PVOID  ExportAddress;
1603   PWORD  OrdinalList;
1604   PDWORD FunctionList, NameList;
1605   PIMAGE_EXPORT_DIRECTORY  ExportDir;
1606   ULONG ExportDirSize;
1607
1608   static BOOLEAN EP = FALSE;
1609
1610   ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1611     RtlImageDirectoryEntryToData(ImportModuleBase,
1612           TRUE,
1613                 IMAGE_DIRECTORY_ENTRY_EXPORT,
1614                 &ExportDirSize);
1615
1616   if (!EP) {
1617     EP = TRUE;
1618     ps("ExportDir %x\n", ExportDir);
1619   }
1620
1621   FunctionList = (PDWORD)((DWORD)ExportDir->AddressOfFunctions + ImportModuleBase);
1622   NameList = (PDWORD)((DWORD)ExportDir->AddressOfNames + ImportModuleBase);
1623   OrdinalList = (PWORD)((DWORD)ExportDir->AddressOfNameOrdinals + ImportModuleBase);
1624
1625   ExportAddress = 0;
1626
1627   if (Name != NULL)
1628     {
1629       for (Idx = 0; Idx < ExportDir->NumberOfNames; Idx++)
1630         {
1631           if (!strcmp(Name, (PCHAR) ((DWORD)ImportModuleBase + NameList[Idx])))
1632                         {
1633               ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1634                 FunctionList[OrdinalList[Idx]]);
1635               break;
1636             }
1637         }
1638     }
1639   else  /*  use hint  */
1640     {
1641       ExportAddress = (PVOID) ((DWORD)ImportModuleBase +
1642
1643         FunctionList[Hint - ExportDir->Base]);
1644     }
1645
1646   if (ExportAddress == 0)
1647     {
1648       ps("Export not found for %d:%s\n",
1649          Hint,
1650          Name != NULL ? Name : "(Ordinal)");
1651       KEBUGCHECK(0);
1652     }
1653   return ExportAddress;
1654 }
1655
1656 #endif /* LIBCAPTIVE */
1657
1658 static PVOID
1659 LdrPEFixupForward(PCHAR ForwardName)
1660 {
1661    CHAR NameBuffer[128];
1662    UNICODE_STRING ModuleName;
1663    PCHAR p;
1664    PMODULE_OBJECT ModuleObject;
1665
1666    DPRINT("LdrPEFixupForward (%s)\n", ForwardName);
1667
1668    strcpy(NameBuffer, ForwardName);
1669    p = strchr(NameBuffer, '.');
1670    if (p == NULL)
1671      {
1672         return NULL;
1673      }
1674
1675    *p = 0;
1676
1677    DPRINT("Driver: %s  Function: %s\n", NameBuffer, p+1);
1678
1679    RtlCreateUnicodeStringFromAsciiz(&ModuleName,
1680                                     NameBuffer);
1681    ModuleObject = LdrGetModuleObject(&ModuleName);
1682    RtlFreeUnicodeString(&ModuleName);
1683
1684    DPRINT("ModuleObject: %p\n", ModuleObject);
1685
1686    if (ModuleObject == NULL)
1687      {
1688         CPRINT("LdrPEFixupForward: failed to find module %s\n", NameBuffer);
1689         return NULL;
1690      }
1691
1692   return(LdrPEGetExportAddress(ModuleObject, p+1, 0));
1693 }
1694
1695 /* EOF */