This commit was manufactured by cvs2svn to create branch 'captive'.
[captive.git] / src / libcaptive / ldr / loader.c
diff --git a/src/libcaptive/ldr/loader.c b/src/libcaptive/ldr/loader.c
deleted file mode 100644 (file)
index 9829310..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/* $Id$
- * reactos ldr/ (loader) emulation of libcaptive
- * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; exactly version 2 of June 1991 is required
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "config.h"
-
-#include "captive/ldr.h"       /* self */
-#include "captive/ldr_exports.h"       /* self */
-#include "reactos/internal/ldr.h"      /* self */
-#include "captive/unicode.h"
-#include "captive/rtl-file.h"
-#include <glib/gtypes.h>
-#include <glib/gmessages.h>
-#include <glib/gmem.h>
-#include "reactos/napi/types.h"
-#include "reactos/internal/kd.h"       /* for KDB_LOADDRIVER_HOOK */
-#include <fcntl.h>
-#include <sys/mman.h>  /* for PROT_READ, MAP_SHARED */
-#include "captive/macros.h"
-#include <stdarg.h>
-#include "reactos/ntos/rtl.h"  /* for InsertTailList() */
-#include "reactos/internal/debug.h"    /* for assert() */
-#include <glib/gutils.h>       /* for g_path_get_basename() */
-#include <gmodule.h>
-#include "captive/options-module.h"
-
-
-/* map: ExportAddress -> (struct captive_ModuleList_patchpoint *) */
-static GHashTable *captive_ModuleList_patchpoint_hash;
-
-/* initialize 'captive_ModuleList_patchpoint_hash' */
-static void captive_ModuleList_patchpoint_hash_init(void)
-{
-       if (captive_ModuleList_patchpoint_hash)
-               return;
-       captive_ModuleList_patchpoint_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
-}
-
-
-/* map: ExportAddress -> (CHAR *)funcname */
-static GHashTable *captive_ModuleList_function_disable_hash;
-
-/* initialize 'captive_ModuleList_function_disable_hash' */
-static void captive_ModuleList_function_disable_hash_init(void)
-{
-       if (captive_ModuleList_function_disable_hash)
-               return;
-       captive_ModuleList_function_disable_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
-}
-
-
-/* reactos/ntoskrnl/ldr/loader.c file-scope global declaration: */
-NTSTATUS LdrProcessModule(PVOID ModuleLoadBase,PUNICODE_STRING ModuleName,PMODULE_OBJECT *ModuleObject);
-PVOID LdrGetExportAddress(PMODULE_OBJECT ModuleObject,char *Name,unsigned short Hint);
-
-
-/* 'ntoskrnl/ldr/loader.c' file-scoped declaration: */
-VOID LdrpBuildModuleBaseName(PUNICODE_STRING BaseName,PUNICODE_STRING FullName);
-
-
-static MODULE_OBJECT *captive_LdrLoadModule_gmodule(const gchar *Filename_utf8,const gchar *Filename_bslash_utf8)
-{
-MODULE_OBJECT *r;
-GModule *gmodule;
-MODULE_TEXT_SECTION *ModuleTextSection;
-gboolean errbool;
-
-       g_return_val_if_fail(Filename_utf8!=NULL,NULL);
-       g_return_val_if_fail(Filename_bslash_utf8!=NULL,NULL);
-       g_return_val_if_fail(TRUE==g_module_supported(),NULL);
-
-       gmodule=g_module_open(Filename_utf8,
-                       0);     /* Flags; !LAZY */
-       if (!gmodule)
-               g_message(g_module_error());
-       g_assert(gmodule!=NULL);
-
-       captive_new0(r);
-
-       errbool=g_module_symbol(gmodule,"DriverEntry",&r->EntryPoint);
-       g_assert(errbool==TRUE);
-
-       r->Base=(PVOID)gmodule;
-       r->Flags=MODULE_FLAG_COFF;      /* some weird value - reactos uses MODULE_FLAG_PE */
-  
-       RtlCreateUnicodeString(&r->FullName,captive_utf8_to_UnicodeString_alloca(Filename_bslash_utf8)->Buffer);
-  LdrpBuildModuleBaseName(&r->BaseName,&r->FullName);
-
-       /* r->Length=0; */
-  
-  /* Insert module */
-       InsertTailList(&ModuleListHead,&r->ListEntry);
-
-       captive_new0(ModuleTextSection);
-       /* ModuleTextSection->Base=0; */
-       /* ModuleTextSection->Length=0; */
-       ModuleTextSection->Name=g_memdup(r->BaseName.Buffer,
-                       (captive_ucs2_strlen(r->BaseName.Buffer)+1)*sizeof(captive_ucs2));
-       /* ModuleTextSection->OptionalHeader=NULL; */
-       InsertTailList(&ModuleTextListHead,&ModuleTextSection->ListEntry);
-       r->TextSection=ModuleTextSection;
-
-       return r;
-}
-
-
-/**
- * captive_LdrLoadModule:
- * @options_module: #captive_options_module structure describing the module to load.
- * Loading of already loaded module is forbidden.
- * @ModuleObjectp: Returns initialized module object.
- *
- * Load and initialize module to reactos using host OS functions.
- *
- * Returns: STATUS_SUCCESS if the module was loaded successfuly during the call.
- */
-NTSTATUS captive_LdrLoadModule(struct captive_options_module *options_module,PMODULE_OBJECT *ModuleObjectp)
-{
-PMODULE_OBJECT Module;
-NTSTATUS err;
-gchar *Filename_utf8=options_module->pathname_utf8;
-gchar *Filename_bslash_utf8,*s;
-UNICODE_STRING *Filename_bslash;
-
-       *ModuleObjectp=NULL;
-
-       /* Filename=~s#/#\\#g -> Filename_bslash to satisfy basename-derivations by reactos. */
-       Filename_bslash_utf8=(/* de-const as we do not change the length */ gchar *)captive_strdup_alloca(Filename_utf8);
-       for (s=Filename_bslash_utf8;(s=strchr(s,'/'));s++)
-               *s='\\';
-       Filename_bslash=captive_utf8_to_UnicodeString_alloca(Filename_bslash_utf8);
-
-       switch (options_module->type) {
-               case CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY: g_assert_not_reached();
-
-               case CAPTIVE_OPTIONS_MODULE_TYPE_PE32:
-                       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Loading module format: %s",G_STRLOC,"MZ/PE-32");
-                       /* examine/relocate the module */
-                       err=LdrProcessModule(options_module->u.pe32.base,Filename_bslash,&Module);
-                       if (!NT_SUCCESS(err)) {
-                               g_error("LdrLoadModule(): LdrProcessModule()=0x%08lX",(gulong)err);
-                               goto err;
-                               }
-                       break;
-
-               case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE:
-                       g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Loading module format: %s",G_STRLOC,"native .so");
-                       Module=captive_LdrLoadModule_gmodule(Filename_utf8,Filename_bslash_utf8);
-                       g_assert(Module!=NULL);
-               }
-
-       /* we were successful */
-       *ModuleObjectp=Module;
-
-       /* Hook for KDB on loading a driver. */
-       KDB_LOADDRIVER_HOOK(Filename_bslash,Module);
-
-       return STATUS_SUCCESS;
-
-err:
-       g_return_val_if_reached(err);
-}
-
-
-NTSTATUS LdrLoadModule(PUNICODE_STRING Filename,PMODULE_OBJECT *ModuleObject)
-{
-       return STATUS_OBJECT_NAME_NOT_FOUND;
-}
-
-
-/**
- * captive_LdrpLoadAndCallImage:
- * @ModuleObjectp: Returns PMODULE_OBJECT successfuly loaded.
- * @options_module: #captive_options_module structure describing the module to load.
- * Loading of already loaded module is forbidden despite original
- * LdrpLoadAndCallImage().
- * @DriverEntry_DriverObject: argument #DriverObject of #PDRIVER_INITIALIZE call.
- * @DriverEntry_RegistryPath: argument #RegistryPath of #PDRIVER_INITIALIZE call.
- *
- * Corresponds to reactos LdrpLoadAndCallImage() but it also provides arguments
- * to pass to #PDRIVER_INITIALIZE call of module driver initialization.
- *
- * Returns: STATUS_SUCCESS if the driver module was loaded and initialized
- * successfuly during this call. Ignore returned @ModuleObjectp if function failed.
- */
-NTSTATUS captive_LdrpLoadAndCallImage(PMODULE_OBJECT *ModuleObjectp,struct captive_options_module *options_module,
-               PDRIVER_OBJECT DriverEntry_DriverObject,PUNICODE_STRING DriverEntry_RegistryPath)
-{
-PDRIVER_INITIALIZE DriverEntry;
-PMODULE_OBJECT ModuleObject_tmp;
-NTSTATUS err;
-
-#if 0  /* TODO */
-       /* check for duplicity */
-       g_return_val_if_fail(LdrGetModuleObject(ModuleName)==NULL,STATUS_IMAGE_ALREADY_LOADED);
-#endif
-
-       /* provide our temporary storage if the caller doesn't want to know ModuleObject address */
-       if (!ModuleObjectp)
-               ModuleObjectp=&ModuleObject_tmp;
-
-       /* load the module */
-       err=captive_LdrLoadModule(options_module,ModuleObjectp);
-       g_return_val_if_fail(NT_SUCCESS(err),err);
-
-       /* initialize the module */
-       DriverEntry=(PDRIVER_INITIALIZE)(*ModuleObjectp)->EntryPoint;
-       err=(*DriverEntry)(DriverEntry_DriverObject,DriverEntry_RegistryPath);
-       if (!NT_SUCCESS(err))
-               goto err_LdrUnloadModule;
-
-       /* assumed STATUS_SUCCESS */
-       return err;
-
-err_LdrUnloadModule:
-       /* errors ignored */
-       LdrUnloadModule(*ModuleObjectp);
-       *ModuleObjectp=NULL;
-/* err: */
-       g_return_val_if_reached(err);
-}
-
-
-/**
- * captive_ModuleList_add_builtin:
- * @FullName_utf8: String to fill in #PMODULE_OBJECT->FullName.
- * @...: (const gchar *sym_name,void *sym_val) symbol list terminated by %NULL.
- *
- * Adds simulated built-in module to #ModuleListHead module list.
- * It can be used for the functionality of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement().
- * libcaptive does not support Ordinals - we just pretend liner (%0-based)
- * Ordinal numbers of the functions in given @... stdargs order.
- *
- * Returns: %TRUE if the module was successfuly added.
- */
-gboolean captive_ModuleList_add_builtin(const gchar *FullName_utf8,...)
-{
-MODULE_OBJECT *ModuleObject;
-BOOLEAN errbool;
-va_list ap;
-const gchar *sym_name;
-const void *sym_val;
-gchar *basename_utf8;
-IMAGE_DOS_HEADER *DosHeader;
-IMAGE_NT_HEADERS *NTHeaders;
-IMAGE_EXPORT_DIRECTORY *ExportDir;
-guint symi,symN;       /* index,number of passed stdarg sym_name/sym_val pairs */
-ptrdiff_t *NameList;   /* filled by sym_name; MODULEOBJECT_BASE_OFFSET_MINUS()ed */
-WORD *OrdinalList;     /* linear list - libcaptive doesn't support Ordinals */
-ptrdiff_t *FunctionList;       /* filled by sym_val; MODULEOBJECT_BASE_OFFSET_MINUS()ed */
-
-       g_return_val_if_fail(FullName_utf8!=NULL,FALSE);
-
-       captive_new0(ModuleObject);
-       /* A lot of offsets in the structures are relative to ModuleObject->Base */
-#define MODULEOBJECT_BASE_OFFSET_MINUS(addr) ((ptrdiff_t)((char *)addr-(char *)ModuleObject->Base))
-
-       ModuleObject->Flags = MODULE_FLAG_PE;
-
-       /* fill ModuleObject->FullName
-        * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but
-        * we put there '/'-based UNIX filenames in libcaptive.
-        */
-       errbool=RtlCreateUnicodeString(&ModuleObject->FullName,captive_utf8_to_UnicodeString_alloca(FullName_utf8)->Buffer);
-       if (!errbool) {
-               g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE");
-               goto err_g_free_ModuleObject;
-               }
-
-       /* fill ModuleObject->BaseName
-        * reactos/ntoskrnl/ldr/loader.c/LdrpBuildModuleBaseName() does this one
-        * but it is 'static' for that file and also it is stricly backslash based.
-        * ModuleObject->FullName should be probably "\\SYSTEM32\\..." style but
-        * we put there '/'-based UNIX filenames in libcaptive.
-        */
-       basename_utf8=g_path_get_basename(FullName_utf8);
-       errbool=RtlCreateUnicodeString(&ModuleObject->BaseName,captive_utf8_to_UnicodeString_alloca(basename_utf8)->Buffer);
-       g_free(basename_utf8);
-       if (!errbool) {
-               g_error("captive_ModuleList_add_builtin: RtlCreateUnicodeString()==FALSE");
-               goto err_g_free_ModuleObject;
-               }
-
-       /* We must satisfy reactos/ntoskrnl/ldr/rtl.c/RtlImageDirectoryEntryToData(,,IMAGE_DIRECTORY_ENTRY_EXPORT)
-        * prepare module headers
-        */
-       captive_new0(DosHeader);
-       ModuleObject->Base=DosHeader;   /* link DosHeader to ModuleObject */
-       DosHeader->e_magic=IMAGE_DOS_MAGIC;
-       captive_new0(NTHeaders);
-       DosHeader->e_lfanew=MODULEOBJECT_BASE_OFFSET_MINUS(NTHeaders);  /* link NTHeaders to DosHeader */
-       NTHeaders->Signature=IMAGE_PE_MAGIC;
-       NTHeaders->OptionalHeader.NumberOfRvaAndSizes=IMAGE_DIRECTORY_ENTRY_EXPORT+1;
-       NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
-                       =sizeof(*ExportDir);    /* in bytes; just prevent LdrPEFixupForward() invocation */
-       captive_new0(ExportDir);
-       NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
-                       =MODULEOBJECT_BASE_OFFSET_MINUS(ExportDir);     /* link ExportDir to NTHeaders */
-       ExportDir->Base=0;      /* base Ordinal number; Ordinals are not supported by libcaptive */
-
-       /* count the number of symbols */
-       va_start(ap,FullName_utf8);
-       for (symN=0;captive_va_arg(sym_name,ap);symN++)
-               captive_va_arg(sym_val,ap);
-       va_end(ap);
-       ExportDir->NumberOfNames=symN;
-       ExportDir->NumberOfFunctions=symN;
-
-       /* allocate and link the symbol tables */
-       captive_newn(NameList,symN);
-       ExportDir->AddressOfNames=(PDWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(NameList);   /* link NameList to ExportDir */
-       captive_newn(OrdinalList,symN);
-       ExportDir->AddressOfNameOrdinals=(PWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(OrdinalList);  /* link OrdinalList to ExportDir */
-       captive_newn(FunctionList,symN);
-       ExportDir->AddressOfFunctions=(PDWORD *)MODULEOBJECT_BASE_OFFSET_MINUS(FunctionList);   /* link FunctionList to ExportDir */
-
-       /* fill in symbol tables */
-       va_start(ap,FullName_utf8);
-       for (symi=0;symi<symN;symi++) {
-               captive_va_arg(sym_name,ap);
-               captive_va_arg(sym_val ,ap);
-               NameList[symi]=MODULEOBJECT_BASE_OFFSET_MINUS(sym_name);
-               OrdinalList[symi]=symi; /* Ordinals are not supported by libcaptive */
-               FunctionList[symi]=MODULEOBJECT_BASE_OFFSET_MINUS(sym_val);
-               }
-       va_end(ap);
-
-       /* successful module info build */
-       InsertTailList(&ModuleListHead,&ModuleObject->ListEntry);
-       return TRUE;
-
-err_g_free_ModuleObject:
-       g_free(ModuleObject);
-/* err */
-       g_return_val_if_reached(FALSE);
-}
-
-
-static gsize instruction_length(const guint8 *instr)
-{
-       if ((instr[0] & 0xF8)==0x50)    /* push %regular-register */
-               return 1;
-       if ((instr[0] & 0xF8)==0x58)    /* pop  %regular-register */
-               return 1;
-       if ((instr[0] & 0xE7)==0x06)    /* push %segment-register */
-               return 1;
-       if ((instr[0] & 0xE7)==0x07 && instr[0]!=0x0F)  /* pop  %segment-register */
-               return 1;
-       switch (instr[0]) {
-               case 0x33:      /* xor GB,Ev */
-                       return 1+1;
-               case 0x64:      /* prefix %fs */
-                       return instruction_length(instr+1);
-               case 0x68:      /* push $quad-byte */
-                       return 1+4;
-               case 0x6A:      /* push $single-byte */
-                       return 1+1;
-               case 0x80:
-                       switch (instr[1]) {
-                               case 0x3D:      /* cmpb $byte,immediate-quad-indirect */
-                                       return 1+1+4+1; /* 80 3D immediate-quad-indirect byte */
-                               case 0x7C:      /* cmpb $byte,#immediate(%reg,1) */
-                                       return 1+1+1+1+1;       /* 80 7C address-mode immediate byte */
-                               default: g_assert_not_reached();
-                               }
-               case 0x83:
-                       switch (instr[1]) {
-                               case 0x01:      /* addl $byte,(%ecx) */
-                                       return 1+1+1;
-                               case 0x3D:      /* cmpl $byte,immediate-quad-indirect */
-                                       return 1+1+4+1; /* 83 3D immediate-quad-indirect byte */
-                               case 0x7C:      /* cmpl $byte,#immediate(%reg,1) */
-                                       return 1+1+1+1+1;       /* 80 7C address-mode immediate byte */
-                               default: g_assert_not_reached();
-                               }
-               case 0x8A:      /* mov ??,?? */
-               case 0x8B:      /* mov Gb,Eb */
-                       switch (instr[1]) {
-                               case 0x0D:      /* mov immediate-quad-indirect,%ecx */
-                                       return 1+1+4;
-                               case 0x15:      /* mov immediate-quad-indirect,%edx */
-                                       return 1+1+4;
-                               case 0x44:      /* mov #offset(%reg,%reg,#mult),%reg */
-                               case 0x4C:      /* mov #offset(%reg,#mult),%reg */
-                               case 0x54:      /* mov #offset(%reg,#mult),%reg */
-                                       return 1+1+1+1; /* 8B 44 address-mode offset */
-                               default: g_assert_not_reached();
-                               }
-               case 0x8D:      /* lea Gb,M */
-                       switch (instr[1]) {
-                               case 0x44:      /* mov #offset(%reg,%reg,#mult),%reg */
-                                       return 4;       /* 8B 44 address-mode offset */
-                               default: g_assert_not_reached();
-                               }
-               case 0x8F:      /* lea Gb,M */
-                       switch (instr[1]) {
-                               case 0x04:
-                                       switch (instr[2]) {
-                                               case 0x24:      /* popl (%esp,1) */
-                                                       return 3;
-                                               default: g_assert_not_reached();
-                                               }
-                               default: g_assert_not_reached();
-                               }
-               case 0x9C:      /* pushf */
-                       return 1;
-               case 0x9D:      /* popf */
-                       return 1;
-               case 0xA1:      /* mov immediate-quad-indirect,%eax */
-                       return 1+4;
-               case 0xB8:      /* mov $immediate-quad,%eax */
-                       return 1+4;
-               case 0xC2:      /* ret $immediate-double */
-                       return 1+2;
-               case 0xCC:      /* int $0x3 */
-                       return 1;
-               case 0xFA:      /* cli */
-                       return 1;
-               case 0xFB:      /* sti */
-                       return 1;
-               case 0xFF:      /* inc/dec Ev */
-                       return 2;
-               default: g_assert_not_reached();
-               }
-       g_assert_not_reached(); /* TODO:fill the table */
-       /* NOTREACHED */
-       return 0;
-}
-
-
-       /* A lot of offsets in the structures are relative to ModuleObject->Base */
-#define MODULEOBJECT_BASE_OFFSET_PLUS(addr) ((gpointer)((char *)addr+(ptrdiff_t)ModuleObject->Base))
-
-static void captive_ModuleList_patch_function_disable
-               (CHAR *funcname,PVOID *ExportAddressp,MODULE_OBJECT *ModuleObject /* user_data */)
-{
-PVOID ExportAddress;
-
-       g_return_if_fail(funcname!=NULL);
-       g_return_if_fail(ExportAddressp!=NULL);
-       g_return_if_fail(ModuleObject!=NULL);
-
-       ExportAddress=(PVOID)MODULEOBJECT_BASE_OFFSET_PLUS(*ExportAddressp);
-       g_return_if_fail(ExportAddress!=NULL);
-
-       /* Some alised name; safe to ignore as we checked for possible W32 binary 0xF4
-        * hits during our initialization in captive_ModuleList_patch().
-        */
-       if (0xF4 /* hlt */ ==*(guint8 *)ExportAddress)
-               return;
-
-       captive_ModuleList_function_disable_hash_init();
-
-       *(guint8 *)ExportAddress=0xF4; /* hlt */
-       /* We may get aliased here; already existing entry is therefore allowed. */
-       g_hash_table_insert(captive_ModuleList_function_disable_hash,
-                       ExportAddress,  /* key */
-                       funcname);      /* value */
-}
-
-
-/**
- * captive_ModuleList_patch:
- * @FullName_utf8: String to find #PMODULE_OBJECT by #FullName.
- * @...: (const gchar *sym_name,void (*sym_val)(void),struct captive_ModuleList_patchpoint *patchpoint) symbol list terminated by %NULL.
- *
- * Patches existing @FullName_utf8 module to use for function named #sym_name
- * pointer to the handler #sym_val. If #patchpoint is not %NULL it gets assigned the original
- * pointer value (used for %pass keyword in #exports.captivesym).
- * 
- * Put here 0xF4 'hlt' instead of 0xCC 'int $0x3; breakpoint'
- * as 'hlt' will generate handled SIGSEGV instead of SIGTRAP which
- * is used by gdb(1) during debugging.
- * See also libcaptive/ps/signal.c/ sigaction_SIGSEGV().
- *
- * Returns: %TRUE if the module was successfuly added.
- */
-gboolean captive_ModuleList_patch(const gchar *FullName_utf8,...)
-{
-MODULE_OBJECT *ModuleObject;
-va_list ap;
-IMAGE_EXPORT_DIRECTORY *ExportDir;
-ptrdiff_t *NameList;   /* filled by sym_name; MODULEOBJECT_BASE_OFFSET_PLUS()ed */
-WORD *OrdinalList;     /* linear list - libcaptive doesn't support Ordinals */
-ptrdiff_t *FunctionList;       /* filled by sym_val; MODULEOBJECT_BASE_OFFSET_PLUS()ed */
-ULONG ExportDirSize;
-USHORT Idx;
-PVOID ExportAddress,*ExportAddressp;
-const gchar *sym_name;
-void (*sym_val)(void);
-struct captive_ModuleList_patchpoint *patchpoint;
-GHashTable *exportdir_hash;
-gboolean errbool;
-
-       g_return_val_if_fail(FullName_utf8!=NULL,FALSE);
-
-       captive_ModuleList_patchpoint_hash_init();
-
-       ModuleObject=LdrGetModuleObject(captive_utf8_to_UnicodeString_alloca(g_path_get_basename(FullName_utf8)));
-       g_return_val_if_fail(ModuleObject!=NULL,FALSE);
-
-       ExportDir=(PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(ModuleObject->Base,
-                       TRUE,IMAGE_DIRECTORY_ENTRY_EXPORT,&ExportDirSize);
-       g_return_val_if_fail(ExportDir!=NULL,FALSE);
-
-       NameList    =MODULEOBJECT_BASE_OFFSET_PLUS(ExportDir->AddressOfNames);
-       OrdinalList =MODULEOBJECT_BASE_OFFSET_PLUS(ExportDir->AddressOfNameOrdinals);
-       FunctionList=MODULEOBJECT_BASE_OFFSET_PLUS(ExportDir->AddressOfFunctions);
-
-       /* map (CHAR *)funcname->(PVOID *)ExportAddressp */
-       exportdir_hash=g_hash_table_new(g_str_hash,g_str_equal);
-
-       /* Initialize 'exportdir_hash' by all W32 exported functions. */
-       for (Idx=0;Idx<ExportDir->NumberOfNames;Idx++) {
-CHAR *funcname=MODULEOBJECT_BASE_OFFSET_PLUS(NameList[Idx]);
-
-               ExportAddressp=(PVOID *)(FunctionList+OrdinalList[Idx]);
-               ExportAddress=(PVOID)MODULEOBJECT_BASE_OFFSET_PLUS(*ExportAddressp);
-               if (0xF4 /* hlt */ ==*(guint8 *)ExportAddress) {
-                       /* FIXME: 'data' type symbols should be permitted to have 0xF4 byte */
-                       g_error("%s: Function already patched although we did not touch it yet: %s",G_STRLOC,funcname);
-                       g_assert_not_reached();
-                       }
-               g_assert(NULL==g_hash_table_lookup(exportdir_hash,funcname));
-               g_hash_table_insert(exportdir_hash,
-                               funcname,       /* key */
-                               ExportAddressp);        /* value */
-               }
-
-       /* Patch wished functions and remove them from 'exportdir_hash'. */
-       va_start(ap,FullName_utf8);
-       while (captive_va_arg(sym_name,ap)) {
-               captive_va_arg(sym_val ,ap);
-               /* 'sym_val' may be NULL if 'data' type && "pass"ed */
-               captive_va_arg(patchpoint,ap);  /* 'data' type if ==NULL */
-               ExportAddressp=g_hash_table_lookup(exportdir_hash,sym_name);
-               if (ExportAddressp==NULL) {
-                       g_message("%s: Function not found for patchpoint (ignoring): %s",G_STRLOC,sym_name);
-                       continue;
-                       }
-               errbool=g_hash_table_remove(exportdir_hash,sym_name);
-               g_assert(errbool==TRUE);
-               if (!sym_val) { /* 'data' type && "pass"ed => do not corrupt it by 0xF4 */
-                       g_assert(!patchpoint);
-                       continue;
-                       }
-               ExportAddress=(PVOID)MODULEOBJECT_BASE_OFFSET_PLUS(*ExportAddressp);
-               *ExportAddressp=(PVOID)MODULEOBJECT_BASE_OFFSET_MINUS(sym_val);
-               if (((ULONG)ExportAddress >= (ULONG)ExportDir) &&
-                               ((ULONG)ExportAddress <  (ULONG)ExportDir + ExportDirSize))
-                       g_assert_not_reached(); /* LdrPEFixupForward() needed */
-               if (!patchpoint) /* 'data' type && !"pass"ed => do not corrupt it by 0xF4 */
-                       continue;
-               patchpoint->orig_w32_func=ExportAddress;
-               if (0xF4 /* hlt */ ==*patchpoint->orig_w32_func)        /* Already patched by name-aliased function? */
-                       continue;
-               g_assert(0xF4 /* hlt */ !=*patchpoint->orig_w32_func);
-               patchpoint->orig_w32_2ndinstr=patchpoint->orig_w32_func
-                               +instruction_length((guint8 *)patchpoint->orig_w32_func);
-               g_assert(0xF4 /* hlt */ !=*patchpoint->orig_w32_2ndinstr);
-               patchpoint->wrap_wrap_func=sym_val;
-               patchpoint->orig_w32_func_byte=*patchpoint->orig_w32_func;
-               patchpoint->orig_w32_2ndinstr_byte=*patchpoint->orig_w32_2ndinstr;
-               patchpoint->through_w32_func=FALSE;
-               g_assert(NULL==g_hash_table_lookup(captive_ModuleList_patchpoint_hash,patchpoint->orig_w32_func));
-               g_hash_table_insert(captive_ModuleList_patchpoint_hash,
-                               patchpoint->orig_w32_func,      /* key */
-                               patchpoint);    /* value */
-               g_assert(NULL==g_hash_table_lookup(captive_ModuleList_patchpoint_hash,patchpoint->orig_w32_2ndinstr));
-               g_hash_table_insert(captive_ModuleList_patchpoint_hash,
-                               patchpoint->orig_w32_2ndinstr,  /* key */
-                               patchpoint);    /* value */
-               *(guint8 *)ExportAddress=0xF4;  /* hlt */
-               }
-       va_end(ap);
-
-       /* The remaining entries of 'exportdir_hash' are W32 native functions
-        * unspecified by .captivesym file; we patch them as not-implemented ones.
-        */
-       g_hash_table_foreach(exportdir_hash,
-                       (GHFunc)captive_ModuleList_patch_function_disable,      /* func */
-                       ModuleObject);  /* used_data; unused */
-
-       g_hash_table_destroy(exportdir_hash);
-
-#undef MODULEOBJECT_BASE_OFFSET_PLUS   /* no longer valid */
-#undef MODULEOBJECT_BASE_OFFSET_MINUS  /* no longer valid */
-       return TRUE;
-}
-
-
-struct captive_ModuleList_patchpoint *captive_ModuleList_patchpoint_find(gconstpointer ExportAddress)
-{
-struct captive_ModuleList_patchpoint *r;
-
-       g_return_val_if_fail(ExportAddress!=NULL,NULL);
-
-       captive_ModuleList_patchpoint_hash_init();
-
-       r=g_hash_table_lookup(captive_ModuleList_patchpoint_hash,ExportAddress);
-       g_return_val_if_fail(r!=NULL,NULL);
-       g_assert(r->orig_w32_func==ExportAddress || r->orig_w32_2ndinstr==ExportAddress);
-
-       return r;
-}
-
-
-G_CONST_RETURN gchar *captive_ModuleList_function_disable_find(gconstpointer ExportAddress)
-{
-       g_return_val_if_fail(ExportAddress!=NULL,NULL);
-
-       return g_hash_table_lookup(captive_ModuleList_function_disable_hash,ExportAddress);     /* funcname */
-}
-
-
-void *captive_Module_GetExportAddress(const gchar *ModuleName_utf8,const gchar *FunctionName)
-{
-MODULE_OBJECT *ModuleObject;
-void *r;
-
-       g_return_val_if_fail(ModuleName_utf8!=NULL,NULL);
-       g_return_val_if_fail(FunctionName!=NULL,NULL);
-
-       ModuleObject=LdrGetModuleObject(captive_utf8_to_UnicodeString_alloca(g_path_get_basename(ModuleName_utf8)));
-       g_return_val_if_fail(ModuleObject!=NULL,NULL);
-
-       r=LdrGetExportAddress(
-                       ModuleObject,   /* ModuleObject */
-                       (/* de-const */char *)FunctionName,     /* Name */
-                       -1);    /*Hint*/
-       g_return_val_if_fail(r!=NULL,NULL);
-
-       return r;
-}