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