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/rtl-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() */
41 /* reactos/ntoskrnl/ldr/loader.c file-scope global declaration: */
42 NTSTATUS LdrProcessModule(PVOID ModuleLoadBase,PUNICODE_STRING ModuleName,PMODULE_OBJECT *ModuleObject);
45 /* 'ntoskrnl/ldr/loader.c' file-scoped declaration: */
46 VOID LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,PUNICODE_STRING FullName);
49 static MODULE_OBJECT *captive_LdrLoadModule_gmodule(const gchar *Filename_utf8)
53 MODULE_TEXT_SECTION *ModuleTextSection;
56 g_return_val_if_fail(Filename_utf8!=NULL,NULL);
57 g_return_val_if_fail(TRUE==g_module_supported(),NULL);
59 gmodule=g_module_open(Filename_utf8,
60 0); /* Flags; !LAZY */
62 g_message(g_module_error());
63 g_assert(gmodule!=NULL);
67 errbool=g_module_symbol(gmodule,"DriverEntry",&r->EntryPoint);
68 g_assert(errbool==TRUE);
70 r->Base=(PVOID)gmodule;
71 r->Flags=MODULE_FLAG_COFF; /* some weird value - reactos uses MODULE_FLAG_PE */
73 RtlCreateUnicodeString(&r->FullName,captive_utf8_to_UnicodeString_alloca(Filename_utf8)->Buffer);
74 LdrpBuildModuleBaseName(&r->BaseName,&r->FullName);
79 InsertTailList(&ModuleListHead,&r->ListEntry);
81 captive_new0(ModuleTextSection);
82 /* ModuleTextSection->Base=0; */
83 /* ModuleTextSection->Length=0; */
84 ModuleTextSection->Name=g_memdup(r->BaseName.Buffer,
85 (captive_ucs2_strlen(r->BaseName.Buffer)+1)*sizeof(captive_ucs2));
86 /* ModuleTextSection->OptionalHeader=NULL; */
87 InsertTailList(&ModuleTextListHead,&ModuleTextSection->ListEntry);
88 r->TextSection=ModuleTextSection;
96 * @Filename: Filename of module to load based on host OS disk.
97 * Loading of already loaded module is forbidden.
98 * @ModuleObject: Returns initialized module object.
100 * Load and initialize module to reactos using host OS functions.
102 * Returns: STATUS_SUCCESS if the module was loaded successfuly during the call.
104 NTSTATUS LdrLoadModule(PUNICODE_STRING Filename,PMODULE_OBJECT *ModuleObjectp)
106 PVOID ModuleLoadBase;
107 PMODULE_OBJECT Module;
109 const gchar *Filename_utf8=captive_UnicodeString_to_utf8_alloca(Filename);
113 /* Open the Module */
114 ModuleLoadBase=captive_rtl_file_mmap(
116 Filename_utf8, /* path */
117 O_RDONLY, /* open_flags */
118 PROT_READ, /* mmap_prot */
119 MAP_SHARED); /* mmap_flags */
120 /* FIXME: convert errno instead of STATUS_INSUFFICIENT_RESOURCES */
121 g_return_val_if_fail(ModuleLoadBase!=NULL,STATUS_INSUFFICIENT_RESOURCES);
123 if ((('M'<<8U)|('Z'<<0U))==GUINT16_FROM_BE(*(const guint16 *)ModuleLoadBase)) {
124 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Loading module format: %s",G_STRLOC,"MZ/PE-32");
125 /* examine/relocate the module */
126 err=LdrProcessModule(ModuleLoadBase,Filename,&Module);
127 if (!NT_SUCCESS(err)) {
128 g_error("LdrLoadModule(): LdrProcessModule()=0x%08lX",err);
129 goto err_captive_rtl_file_munmap;
133 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Loading module format: %s",G_STRLOC,"native .so");
134 Module=captive_LdrLoadModule_gmodule(Filename_utf8);
135 g_assert(Module!=NULL);
138 /* we were successful */
139 captive_rtl_file_munmap(ModuleLoadBase);
140 *ModuleObjectp=Module;
142 /* Hook for KDB on loading a driver. */
143 KDB_LOADDRIVER_HOOK(Filename,Module);
145 return STATUS_SUCCESS;
147 /* Error recoveries */
148 err_captive_rtl_file_munmap:
149 captive_rtl_file_munmap(ModuleLoadBase);
151 g_return_val_if_reached(err);
156 * captive_LdrpLoadAndCallImage:
157 * @ModuleObjectp: Returns PMODULE_OBJECT successfuly loaded.
158 * @ModuleName: Filename of module to load based on host OS disk.
159 * Loading of already loaded module is forbidden despite original
160 * LdrpLoadAndCallImage().
161 * @DriverEntry_DriverObject: argument #DriverObject of #PDRIVER_INITIALIZE call.
162 * @DriverEntry_RegistryPath: argument #RegistryPath of #PDRIVER_INITIALIZE call.
164 * Corresponds to reactos LdrpLoadAndCallImage() but it also provides arguments
165 * to pass to #PDRIVER_INITIALIZE call of module driver initialization.
167 * Returns: STATUS_SUCCESS if the driver module was loaded and initialized
168 * successfuly during this call. Ignore returned @ModuleObjectp if function failed.
170 NTSTATUS captive_LdrpLoadAndCallImage(PMODULE_OBJECT *ModuleObjectp,PUNICODE_STRING ModuleName,
171 PDRIVER_OBJECT DriverEntry_DriverObject,PUNICODE_STRING DriverEntry_RegistryPath)
173 PDRIVER_INITIALIZE DriverEntry;
174 PMODULE_OBJECT ModuleObject_tmp;
177 /* check for duplicity */
178 g_return_val_if_fail(LdrGetModuleObject(ModuleName)==NULL,STATUS_IMAGE_ALREADY_LOADED);
180 /* provide our temporary storage if the caller doesn't want to know ModuleObject address */
182 ModuleObjectp=&ModuleObject_tmp;
184 /* load the module */
185 err=LdrLoadModule(ModuleName,ModuleObjectp);
186 g_return_val_if_fail(NT_SUCCESS(err),err);
188 /* initialize the module */
189 DriverEntry=(PDRIVER_INITIALIZE)(*ModuleObjectp)->EntryPoint;
190 err=(*DriverEntry)(DriverEntry_DriverObject,DriverEntry_RegistryPath);
191 if (!NT_SUCCESS(err))
192 goto err_LdrUnloadModule;
194 /* assumed STATUS_SUCCESS */
199 LdrUnloadModule(*ModuleObjectp);
202 g_return_val_if_reached(err);
207 * captive_ModuleList_add_builtin:
208 * @FullName_utf8: String to fill in #PMODULE_OBJECT->FullName.
209 * @...: (const gchar *sym_name,void *sym_val) symbol list terminated by %NULL.
211 * Adds simulated built-in module to #ModuleListHead module list.
212 * It can be used for the functionality of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement().
213 * libcaptive does not support Ordinals - we just pretend liner (%0-based)
214 * Ordinal numbers of the functions in given @... stdargs order.
216 * Returns: %TRUE if the module was successfuly added.
218 gboolean captive_ModuleList_add_builtin(const gchar *FullName_utf8,...)
220 MODULE_OBJECT *ModuleObject;
223 const gchar *sym_name;
225 gchar *basename_utf8;
226 IMAGE_DOS_HEADER *DosHeader;
227 IMAGE_NT_HEADERS *NTHeaders;
228 IMAGE_EXPORT_DIRECTORY *ExportDir;
229 guint symi,symN; /* index,number of passed stdarg sym_name/sym_val pairs */
230 ptrdiff_t *NameList; /* filled by sym_name; MODULEOBJECT_BASE_OFFSET()ed */
231 WORD *OrdinalList; /* linear list - libcaptive doesn't support Ordinals */
232 ptrdiff_t *FunctionList; /* filled by sym_val; MODULEOBJECT_BASE_OFFSET()ed */
234 g_return_val_if_fail(FullName_utf8!=NULL,FALSE);
236 captive_new0(ModuleObject);
237 /* A lot of offsets in the structures are relative to ModuleObject->Base */
238 #define MODULEOBJECT_BASE_OFFSET(addr) ((ptrdiff_t)((char *)addr-(char *)ModuleObject->Base))
240 ModuleObject->Flags = MODULE_FLAG_PE;
242 /* fill ModuleObject->FullName
243 * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but
244 * we put there '/'-based UNIX filenames in libcaptive.
246 errbool=RtlCreateUnicodeString(&ModuleObject->FullName,captive_utf8_to_UnicodeString_alloca(FullName_utf8)->Buffer);
248 g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE");
249 goto err_g_free_ModuleObject;
252 /* fill ModuleObject->BaseName
253 * reactos/ntoskrnl/ldr/loader.c/LdrpBuildModuleBaseName() does this one
254 * but it is 'static' for that file and also it is stricly backslash based.
255 * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but
256 * we put there '/'-based UNIX filenames in libcaptive.
258 basename_utf8=g_path_get_basename(FullName_utf8);
259 errbool=RtlCreateUnicodeString(&ModuleObject->BaseName,captive_utf8_to_UnicodeString_alloca(basename_utf8)->Buffer);
260 g_free(basename_utf8);
262 g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE");
263 goto err_g_free_ModuleObject;
266 /* We must satisfy reactos/ntoskrnl/ldr/rtl.c/RtlImageDirectoryEntryToData(,,IMAGE_DIRECTORY_ENTRY_EXPORT)
267 * prepare module headers
269 captive_new0(DosHeader);
270 ModuleObject->Base=DosHeader; /* link DosHeader to ModuleObject */
271 DosHeader->e_magic=IMAGE_DOS_MAGIC;
272 captive_new0(NTHeaders);
273 DosHeader->e_lfanew=MODULEOBJECT_BASE_OFFSET(NTHeaders); /* link NTHeaders to DosHeader */
274 NTHeaders->Signature=IMAGE_PE_MAGIC;
275 NTHeaders->OptionalHeader.NumberOfRvaAndSizes=IMAGE_DIRECTORY_ENTRY_EXPORT+1;
276 NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
277 =sizeof(*ExportDir); /* in bytes; just prevent LdrPEFixupForward() invocation */
278 captive_new0(ExportDir);
279 NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
280 =MODULEOBJECT_BASE_OFFSET(ExportDir); /* link ExportDir to NTHeaders */
281 ExportDir->Base=0; /* base Ordinal number; Ordinals are not supported by libcaptive */
283 /* count the number of symbols */
284 va_start(ap,FullName_utf8);
285 for (symN=0;captive_va_arg(sym_name,ap);symN++)
286 captive_va_arg(sym_val,ap);
288 ExportDir->NumberOfNames=symN;
289 ExportDir->NumberOfFunctions=symN;
291 /* allocate and link the symbol tables */
292 captive_newn(NameList,symN);
293 ExportDir->AddressOfNames=(PDWORD *)MODULEOBJECT_BASE_OFFSET(NameList); /* link NameList to ExportDir */
294 captive_newn(OrdinalList,symN);
295 ExportDir->AddressOfNameOrdinals=(PWORD *)MODULEOBJECT_BASE_OFFSET(OrdinalList); /* link OrdinalList to ExportDir */
296 captive_newn(FunctionList,symN);
297 ExportDir->AddressOfFunctions=(PDWORD *)MODULEOBJECT_BASE_OFFSET(FunctionList); /* link FunctionList to ExportDir */
299 /* fill in symbol tables */
300 va_start(ap,FullName_utf8);
301 for (symi=0;symi<symN;symi++) {
302 captive_va_arg(sym_name,ap);
303 captive_va_arg(sym_val ,ap);
304 NameList[symi]=MODULEOBJECT_BASE_OFFSET(sym_name);
305 OrdinalList[symi]=symi; /* Ordinals are not supported by libcaptive */
306 FunctionList[symi]=MODULEOBJECT_BASE_OFFSET(sym_val);
310 /* successful module info build */
311 InsertTailList(&ModuleListHead,&ModuleObject->ListEntry);
312 #undef MODULEOBJECT_BASE_OFFSET /* no longer valid */
315 err_g_free_ModuleObject:
316 g_free(ModuleObject);
318 g_return_val_if_reached(FALSE);