2 * reactos ldr/ (loader) emulation of libcaptive
3 * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "captive/ldr.h" /* self */
23 #include "reactos/internal/ldr.h" /* self */
24 #include "captive/unicode.h"
25 #include "captive/file.h"
26 #include <glib/gtypes.h>
27 #include <glib/gmessages.h>
28 #include <glib/gmem.h>
29 #include "reactos/napi/types.h"
30 #include "reactos/internal/kd.h" /* for KDB_LOADDRIVER_HOOK */
32 #include <sys/mman.h> /* for PROT_READ, MAP_SHARED */
33 #include "captive/macros.h"
35 #include "reactos/ddk/rtl.h" /* for InsertTailList() */
36 #include "reactos/internal/debug.h" /* for assert() */
37 #include <glib/gutils.h> /* for g_path_get_basename() */
40 /* reactos/ntoskrnl/ldr/loader.c file-scope global declaration: */
41 NTSTATUS LdrProcessModule(PVOID ModuleLoadBase,PUNICODE_STRING ModuleName,PMODULE_OBJECT *ModuleObject);
46 * @Filename: Filename of module to load based on host OS disk.
47 * Loading of already loaded module is forbidden.
48 * @ModuleObject: Returns initialized module object.
50 * Load and initialize module to reactos using host OS functions.
52 * Returns: STATUS_SUCCESS if the module was loaded successfuly during the call.
54 NTSTATUS LdrLoadModule(PUNICODE_STRING Filename,PMODULE_OBJECT *ModuleObjectp)
57 PMODULE_OBJECT Module;
63 ModuleLoadBase=captive_file_mmap(
65 captive_UnicodeString_to_utf8_alloca(Filename), /* path */
66 O_RDONLY, /* open_flags */
67 PROT_READ, /* mmap_prot */
68 MAP_SHARED); /* mmap_flags */
69 /* FIXME: convert errno instead of STATUS_INSUFFICIENT_RESOURCES */
70 g_return_val_if_fail(ModuleLoadBase!=NULL,STATUS_INSUFFICIENT_RESOURCES);
72 /* examine/relocate the module */
73 err=LdrProcessModule(ModuleLoadBase,Filename,&Module);
74 if (!NT_SUCCESS(err)) {
75 g_error("LdrLoadModule(): LdrProcessModule()=0x%08lX",err);
76 goto err_captive_file_munmap;
79 /* we were successful */
80 captive_file_munmap(ModuleLoadBase);
81 *ModuleObjectp=Module;
83 /* Hook for KDB on loading a driver. */
84 KDB_LOADDRIVER_HOOK(Filename,Module);
86 return STATUS_SUCCESS;
88 /* Error recoveries */
89 err_captive_file_munmap:
90 captive_file_munmap(ModuleLoadBase);
92 g_return_val_if_reached(err);
97 * captive_LdrpLoadAndCallImage:
98 * @ModuleObjectp: Returns PMODULE_OBJECT successfuly loaded.
99 * @ModuleName: Filename of module to load based on host OS disk.
100 * Loading of already loaded module is forbidden despite original
101 * LdrpLoadAndCallImage().
102 * @DriverEntry_DriverObject: argument #DriverObject of #PDRIVER_INITIALIZE call.
103 * @DriverEntry_RegistryPath: argument #RegistryPath of #PDRIVER_INITIALIZE call.
105 * Corresponds to reactos LdrpLoadAndCallImage() but it also provides arguments
106 * to pass to #PDRIVER_INITIALIZE call of module driver initialization.
108 * Returns: STATUS_SUCCESS if the driver module was loaded and initialized
109 * successfuly during this call. Ignore returned @ModuleObjectp if function failed.
111 NTSTATUS captive_LdrpLoadAndCallImage(PMODULE_OBJECT *ModuleObjectp,PUNICODE_STRING ModuleName,
112 PDRIVER_OBJECT DriverEntry_DriverObject,PUNICODE_STRING DriverEntry_RegistryPath)
114 PDRIVER_INITIALIZE DriverEntry;
115 PMODULE_OBJECT ModuleObject_tmp;
118 /* check for duplicity */
119 g_return_val_if_fail(LdrGetModuleObject(ModuleName)==NULL,STATUS_IMAGE_ALREADY_LOADED);
121 /* provide our temporary storage if the caller doesn't want to know ModuleObject address */
123 ModuleObjectp=&ModuleObject_tmp;
125 /* load the module */
126 err=LdrLoadModule(ModuleName,ModuleObjectp);
127 g_return_val_if_fail(NT_SUCCESS(err),err);
129 /* initialize the module */
130 DriverEntry=(PDRIVER_INITIALIZE)(*ModuleObjectp)->EntryPoint;
131 err=(*DriverEntry)(DriverEntry_DriverObject,DriverEntry_RegistryPath);
132 if (!NT_SUCCESS(err))
133 goto err_LdrUnloadModule;
135 /* assumed STATUS_SUCCESS */
140 LdrUnloadModule(*ModuleObjectp);
143 g_return_val_if_reached(err);
148 * captive_ModuleList_add_builtin:
149 * @FullName_utf8: String to fill in #PMODULE_OBJECT->FullName.
150 * @...: (const gchar *sym_name,void *sym_val) symbol list terminated by %NULL.
152 * Adds simulated built-in module to #ModuleListHead module list.
153 * It can be used for the functionality of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement().
154 * libcaptive does not support Ordinals - we just pretend liner (%0-based)
155 * Ordinal numbers of the functions in given @... stdargs order.
157 * Returns: %TRUE if the module was successfuly added.
159 gboolean captive_ModuleList_add_builtin(const gchar *FullName_utf8,...)
161 MODULE_OBJECT *ModuleObject;
164 const gchar *sym_name;
166 gchar *basename_utf8;
167 IMAGE_DOS_HEADER *DosHeader;
168 IMAGE_NT_HEADERS *NTHeaders;
169 IMAGE_EXPORT_DIRECTORY *ExportDir;
170 guint symi,symN; /* index,number of passed stdarg sym_name/sym_val pairs */
171 ptrdiff_t *NameList; /* filled by sym_name; MODULEOBJECT_BASE_OFFSET()ed */
172 WORD *OrdinalList; /* linear list - libcaptive doesn't support Ordinals */
173 ptrdiff_t *FunctionList; /* filled by sym_val; MODULEOBJECT_BASE_OFFSET()ed */
175 g_return_val_if_fail(FullName_utf8!=NULL,FALSE);
177 captive_new0(ModuleObject);
178 /* A lot of offsets in the structures are relative to ModuleObject->Base */
179 #define MODULEOBJECT_BASE_OFFSET(addr) ((ptrdiff_t)((char *)addr-(char *)ModuleObject->Base))
181 ModuleObject->Flags = MODULE_FLAG_PE;
183 /* fill ModuleObject->FullName
184 * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but
185 * we put there '/'-based UNIX filenames in libcaptive.
187 errbool=RtlCreateUnicodeString(&ModuleObject->FullName,captive_utf8_to_UnicodeString_alloca(FullName_utf8)->Buffer);
189 g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE");
190 goto err_g_free_ModuleObject;
193 /* fill ModuleObject->BaseName
194 * reactos/ntoskrnl/ldr/loader.c/LdrpBuildModuleBaseName() does this one
195 * but it is 'static' for that file and also it is stricly backslash based.
196 * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but
197 * we put there '/'-based UNIX filenames in libcaptive.
199 basename_utf8=g_path_get_basename(FullName_utf8);
200 errbool=RtlCreateUnicodeString(&ModuleObject->BaseName,captive_utf8_to_UnicodeString_alloca(basename_utf8)->Buffer);
201 g_free(basename_utf8);
203 g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE");
204 goto err_g_free_ModuleObject;
207 /* We must satisfy reactos/ntoskrnl/ldr/rtl.c/RtlImageDirectoryEntryToData(,,IMAGE_DIRECTORY_ENTRY_EXPORT)
208 * prepare module headers
210 captive_new0(DosHeader);
211 ModuleObject->Base=DosHeader; /* link DosHeader to ModuleObject */
212 DosHeader->e_magic=IMAGE_DOS_MAGIC;
213 captive_new0(NTHeaders);
214 DosHeader->e_lfanew=MODULEOBJECT_BASE_OFFSET(NTHeaders); /* link NTHeaders to DosHeader */
215 NTHeaders->Signature=IMAGE_PE_MAGIC;
216 NTHeaders->OptionalHeader.NumberOfRvaAndSizes=IMAGE_DIRECTORY_ENTRY_EXPORT+1;
217 NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
218 =sizeof(*ExportDir); /* in bytes; just prevent LdrPEFixupForward() invocation */
219 captive_new0(ExportDir);
220 NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
221 =MODULEOBJECT_BASE_OFFSET(ExportDir); /* link ExportDir to NTHeaders */
222 ExportDir->Base=0; /* base Ordinal number; Ordinals are not supported by libcaptive */
224 /* count the number of symbols */
225 va_start(ap,FullName_utf8);
226 for (symN=0;captive_va_arg(sym_name,ap);symN++)
227 captive_va_arg(sym_val,ap);
229 ExportDir->NumberOfNames=symN;
230 ExportDir->NumberOfFunctions=symN;
232 /* allocate and link the symbol tables */
233 captive_newn(NameList,symN);
234 ExportDir->AddressOfNames=(PDWORD *)MODULEOBJECT_BASE_OFFSET(NameList); /* link NameList to ExportDir */
235 captive_newn(OrdinalList,symN);
236 ExportDir->AddressOfNameOrdinals=(PWORD *)MODULEOBJECT_BASE_OFFSET(OrdinalList); /* link OrdinalList to ExportDir */
237 captive_newn(FunctionList,symN);
238 ExportDir->AddressOfFunctions=(PDWORD *)MODULEOBJECT_BASE_OFFSET(FunctionList); /* link FunctionList to ExportDir */
240 /* fill in symbol tables */
241 va_start(ap,FullName_utf8);
242 for (symi=0;symi<symN;symi++) {
243 captive_va_arg(sym_name,ap);
244 captive_va_arg(sym_val ,ap);
245 NameList[symi]=MODULEOBJECT_BASE_OFFSET(sym_name);
246 OrdinalList[symi]=symi; /* Ordinals are not supported by libcaptive */
247 FunctionList[symi]=MODULEOBJECT_BASE_OFFSET(sym_val);
251 /* successful module info build */
252 InsertTailList(&ModuleListHead,&ModuleObject->ListEntry);
253 #undef MODULEOBJECT_BASE_OFFSET /* no longer valid */
256 err_g_free_ModuleObject:
257 g_free(ModuleObject);
259 g_return_val_if_reached(FALSE);