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