2004-10-02 Casper S. Hornstrup <chorns@users.sourceforge.net>
authorCasper Hornstrup <chorns@users.sourceforge.net>
Sat, 2 Oct 2004 08:44:54 +0000 (08:44 +0000)
committerCasper Hornstrup <chorns@users.sourceforge.net>
Sat, 2 Oct 2004 08:44:54 +0000 (08:44 +0000)
* lib/gdiplus/tests/.cvsignore: Ignore _hooks.c and _stubs.S.
* lib/gdiplus/tests/Makefile (TARGET_OBJECTS): Remove passthrough.o and
add _hooks.o and _stubs.o.
* lib/gdiplus/tests/tests/test-1.c: Test API hooking.
* regtests/shared/regtests.h: Add support for API hooking.
* tools/helper.mk: Generate stubs.
* tools/regtests.c: Add support for generating stubs and hooks.
* lib/gdiplus/tests/passthrough.c: Remove.
* lib/gdiplus/tests/stubs.tst: New file.

svn path=/trunk/; revision=11147

reactos/ChangeLog
reactos/lib/gdiplus/tests/.cvsignore
reactos/lib/gdiplus/tests/Makefile
reactos/lib/gdiplus/tests/passthrough.c [deleted file]
reactos/lib/gdiplus/tests/stubs.tst [new file with mode: 0644]
reactos/lib/gdiplus/tests/tests/test-1.c
reactos/regtests/shared/regtests.h
reactos/tools/helper.mk
reactos/tools/regtests.c

index 342bc54..b15df4f 100644 (file)
@@ -1,3 +1,15 @@
+2004-10-02  Casper S. Hornstrup  <chorns@users.sourceforge.net>
+
+       * lib/gdiplus/tests/.cvsignore: Ignore _hooks.c and _stubs.S.
+       * lib/gdiplus/tests/Makefile (TARGET_OBJECTS): Remove passthrough.o and
+       add _hooks.o and _stubs.o.
+       * lib/gdiplus/tests/tests/test-1.c: Test API hooking.
+       * regtests/shared/regtests.h: Add support for API hooking.
+       * tools/helper.mk: Generate stubs.
+       * tools/regtests.c: Add support for generating stubs and hooks.
+       * lib/gdiplus/tests/passthrough.c: Remove.
+       * lib/gdiplus/tests/stubs.tst: New file.
+
 2004-09-23  Casper S. Hornstrup  <chorns@users.sourceforge.net>
 
        * lib/msafd/makefile (TARGET_CFLAGS): Don't define DBG.
index 576b35e..f234ac5 100644 (file)
@@ -1,5 +1,7 @@
+_hooks.c
 _regtests.c
 _rtstub.c
+_stubs.S
 Makefile.tests
 *.d
 *.o
index 9149f8a..b82159e 100644 (file)
@@ -15,20 +15,23 @@ TARGET_CFLAGS = \
  -D__USE_W32API \
  -DWINVER=0x0600 \
  -D_WIN32_WINNT=0x0501 \
 -I$(REGTESTS_PATH_INC)
+ -I$(REGTESTS_PATH_INC)
 
 -include Makefile.tests
 
 TARGET_OBJECTS = \
   _regtests.o \
-  passthrough.o \
+  _hooks.o \
+  _stubs.o \
   $(addprefix tests/, $(TESTS))
 
 include $(PATH_TO_TOP)/rules.mak
 
 include $(TOOLS_PATH)/helper.mk
 
+LIBS = ../gdiplus.a
+
 run: all
-       @$(CC) -o _runtest.exe _rtstub.o regtests.a $(SDK_PATH_LIB)/rtshared.a ../gdiplus.a
+       @$(CC) -o _runtest.exe _rtstub.o regtests.a $(SDK_PATH_LIB)/rtshared.a $(LIBS)
        @_runtest.exe
        @$(RM) _runtest.exe
diff --git a/reactos/lib/gdiplus/tests/passthrough.c b/reactos/lib/gdiplus/tests/passthrough.c
deleted file mode 100644 (file)
index be7ccab..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <windows.h>
-#define NTOS_MODE_USER
-#include <ntos.h>
-#include "regtests.h"
-
-static PVOID
-GetFunction(LPSTR FileName,
-  LPSTR FunctionName)
-{
-  HMODULE hModule;
-  PVOID Function;
-
-  hModule = GetModuleHandleA(FileName);
-  if (hModule != NULL) 
-    {
-      Function = GetProcAddress(hModule, FunctionName);
-    }
-  else
-         {
-      hModule = LoadLibraryA(FileName);
-      if (hModule != NULL)
-        {
-          Function = GetProcAddress(hModule, FunctionName);
-          //FreeLibrary(hModule);
-        }
-    }
-  return Function;
-}
-
-typedef PVOID STDCALL (*RTL_ALLOCATE_HEAP)(PVOID a1, ULONG a2, ULONG a3);
-
-PVOID STDCALL
-RtlAllocateHeap(PVOID a1,
-  ULONG a2,
-  ULONG a3)
-{
-  RTL_ALLOCATE_HEAP p;
-  p = GetFunction("ntdll.dll", "RtlAllocateHeap");
-  return p(a1, a2, a3);
-}
-
-BOOLEAN STDCALL
-RtlFreeHeap(
-  HANDLE heap,
-  ULONG flags,
-  PVOID ptr)
-{
-  return TRUE;
-}
diff --git a/reactos/lib/gdiplus/tests/stubs.tst b/reactos/lib/gdiplus/tests/stubs.tst
new file mode 100644 (file)
index 0000000..512ef08
--- /dev/null
@@ -0,0 +1,3 @@
+ntdll.dll RtlAllocateHeap@12
+ntdll.dll RtlFreeHeap@12
+msvcrt.dll  printf
index 60a12d4..ec3e11e 100644 (file)
@@ -3,9 +3,36 @@
 
 #include "regtests.h"
 
+BOOL
+ReturnTrue()
+{
+  return TRUE;
+}
+
+static BOOL MyRtlFreeHeapCalled = FALSE;
+
+VOID STDCALL
+MyRtlFreeHeap(ULONG a1, ULONG a2, ULONG a3)
+{
+  MyRtlFreeHeapCalled = TRUE;
+}
+
+extern VOID STDCALL
+RtlFreeHeap(ULONG a1, ULONG a2, ULONG a3);
+
+HOOK Hooks[] =
+{
+  {"RtlFreeHeap", MyRtlFreeHeap}
+};
+
 static int
 RunTest(char *Buffer)
 {
+  _SetHooks(Hooks);
+  RtlFreeHeap(0,0,0);
+  FAIL_IF_FALSE(MyRtlFreeHeapCalled, "RtlFreeHeap() must be called.");
+
+  FAIL_IF_FALSE(ReturnTrue(), "ReturnTrue() must always return TRUE.");
   return TS_OK;
 }
 
index 631c84e..03620c0 100755 (executable)
@@ -7,6 +7,7 @@
  *      06-07-2003  CSH  Created
  */
 #include <stdio.h>
+#include <string.h>
 #include <windows.h>
 
 /* Valid values for Command parameter of TestRoutine */
@@ -84,3 +85,103 @@ extern VOID PerformTests(TestOutputRoutine OutputRoutine, LPSTR TestName);
 /* Routines provided by the driver */
 extern PVOID AllocateMemory(ULONG Size);
 extern VOID FreeMemory(PVOID Base);
+
+
+typedef struct _API_DESCRIPTION
+{
+  PCHAR FileName;
+  PCHAR FunctionName;
+  PVOID FunctionAddress;
+  PVOID MockFunctionAddress;
+} API_DESCRIPTION, *PAPI_DESCRIPTION;
+
+extern API_DESCRIPTION ExternalDependencies[];
+extern ULONG MaxExternalDependency;
+
+static inline PVOID
+FrameworkGetFunction(PAPI_DESCRIPTION ApiDescription)
+{
+  HMODULE hModule;
+  PVOID Function;
+
+  hModule = GetModuleHandleA(ApiDescription->FileName);
+  if (hModule != NULL) 
+    {
+      Function = GetProcAddress(hModule, ApiDescription->FunctionName);
+    }
+  else
+         {
+      hModule = LoadLibraryA(ApiDescription->FileName);
+      if (hModule != NULL)
+        {
+          Function = GetProcAddress(hModule, ApiDescription->FunctionName);
+          //FreeLibrary(hModule);
+        }
+    }
+  return Function;
+}
+
+static inline PVOID STDCALL
+FrameworkGetHookInternal(ULONG index)
+{
+  PVOID address;
+
+  if (index > MaxExternalDependency)
+    return NULL;
+
+  if (ExternalDependencies[index].MockFunctionAddress != NULL)
+    return ExternalDependencies[index].MockFunctionAddress;
+
+  if (ExternalDependencies[index].FunctionAddress != NULL)
+    return ExternalDependencies[index].FunctionAddress;
+
+  address = FrameworkGetFunction(&ExternalDependencies[index]);
+  ExternalDependencies[index].FunctionAddress = address;
+  return address;
+}
+
+
+static inline VOID
+_SetHook(PCHAR name,
+  PVOID address)
+{
+  PAPI_DESCRIPTION api;
+  ULONG index;
+
+  for (index = 0; index <= MaxExternalDependency; index++)
+    {
+      api = &ExternalDependencies[index];
+      if (strcmp(api->FunctionName, name) == 0)
+        {
+          api->FunctionAddress = address;
+          return;
+        }
+    }
+}
+
+typedef struct _HOOK
+{
+  PCHAR FunctionName;
+  PVOID FunctionAddress;
+} HOOK, *PHOOK;
+
+static inline VOID
+_SetHooks(PHOOK hookTable)
+{
+  PHOOK hook;
+
+  hook = &hookTable[0];
+  _SetHook(hook->FunctionName,
+    hook->FunctionAddress);
+}
+
+static inline VOID
+_UnsetHooks(PHOOK hookTable)
+{
+  PHOOK hook;
+
+  hook = &hookTable[0];
+  _SetHook(hook->FunctionName,
+    NULL);
+}
index 1f92c99..c1ea98c 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: helper.mk,v 1.80 2004/09/16 10:25:17 gvg Exp $
+# $Id: helper.mk,v 1.81 2004/10/02 08:44:54 chorns Exp $
 #
 # Helper makefile for ReactOS modules
 # Variables this makefile accepts:
@@ -977,6 +977,7 @@ $(REGTEST_TARGETS): $(REGTEST_TESTS)
 ifeq ($(MK_MODE),user)
 ifeq ($(TARGET_BUILDENV_TEST),yes)
        $(REGTESTS) ./tests/tests ./tests/_regtests.c ./tests/Makefile.tests -e ./tests/_rtstub.c
+       $(REGTESTS) -s ./tests/stubs.tst ./tests/_stubs.S ./tests/_hooks.c
 else
        $(REGTESTS) ./tests/tests ./tests/_regtests.c ./tests/Makefile.tests -u ./tests/_rtstub.c
 endif
index 14921ea..1a56c1d 100755 (executable)
@@ -9,6 +9,7 @@
 #include <sys/stat.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
 #ifdef WIN32
 #include <io.h>
@@ -20,7 +21,6 @@
 #include <dirent.h>
 #include <unistd.h>
 #endif
-#include <ctype.h>
 #ifndef MAX_PATH
 #define MAX_PATH 260
 #endif
@@ -556,17 +556,208 @@ static char EXESTUB[] =
   "  return 0;\n"
   "}\n";
 
+static char STUBS_HEADER[] =
+  "/* This file is autogenerated. */\n"
+  "passthrough:\n"
+  "  call _FrameworkGetHook@4\n"
+  "  test %eax, %eax\n"
+  "  je .return\n"
+  "  jmp *%eax\n"
+  ".return:\n"
+  "  /* This will most likely corrupt the stack */\n"
+  "  ret\n"
+  "\n";
+
+static char HOOKS_HEADER[] =
+  "/* This file is autogenerated. */\n"
+  "#include <windows.h>\n"
+  "#include \"regtests.h\"\n"
+  "\n"
+  "API_DESCRIPTION ExternalDependencies[] =\n"
+  "{\n";
+
+static char HOOKS_FOOTER[] =
+  "};\n"
+  "\n"
+  "#define ExternalDependencyCount %d\n"
+  "ULONG MaxExternalDependency = ExternalDependencyCount - 1;\n"
+  "\n"
+  "PVOID STDCALL\n"
+  "FrameworkGetHook(ULONG index)\n"
+  "{\n"
+  "  return FrameworkGetHookInternal(index);\n"
+  "}\n";
+
 static char HELP[] =
   "REGTESTS path file makefile [-u umstubfile] [-k kmstubfile] [-e exestubfile]\n"
+  "REGTESTS -s stublistfile stubsfile hooksfile\n"
   "\n"
-  "  path        Path to files\n"
-  "  file        Registration file to create\n"
-  "  makefile    Makefile to create\n"
-  "  umstubfile  Optional stub for running tests internal to a user-mode module\n"
-  "  kmstubfile  Optional stub for running tests internal to a kernel-mode module\n"
-  "  exestubfile Optional stub for running tests internal to a module in the build environment\n";
+  "  path         Path to files\n"
+  "  file         Registration file to create\n"
+  "  makefile     Makefile to create\n"
+  "  umstubfile   Optional stub for running tests internal to a user-mode module\n"
+  "  kmstubfile   Optional stub for running tests internal to a kernel-mode module\n"
+  "  exestubfile  Optional stub for running tests internal to a module in the build environment\n"
+  "  stublistfile File with descriptions of stubs\n"
+  "  stubsfile    File with stubs to create\n"
+  "  hooksfile    File with hooks to create\n";
+
+#define INPUT_BUFFER_SIZE 255
+
+void
+write_stubs_header(FILE * out)
+{
+  fputs(STUBS_HEADER, out);
+}
 
-int main(int argc,
+void
+write_hooks_header(FILE * out)
+{
+  fputs(HOOKS_HEADER, out);
+}
+
+void
+write_hooks_footer(FILE *hooks_out, unsigned long nr_stubs)
+{
+  fprintf(hooks_out, HOOKS_FOOTER, nr_stubs);
+}
+
+char *
+get_undecorate_name(char *buf,
+  char *decoratedname)
+{
+  int start = 0;
+  int end = 0;
+
+  while (start < strlen(decoratedname) && decoratedname[start] == '@')
+    {
+      start++;
+    }
+  strcpy(buf, &decoratedname[start]);
+  end = strlen(buf) - 1;
+  while (end > 0 && isdigit(buf[end]))
+    {
+      end--;
+    }
+  if (buf[end] == '@')
+    {
+      buf[end] = 0;
+    }
+  return buf;
+}
+
+void
+write_stub(FILE *stubs_out, FILE *hooks_out, char *dllname,
+  char *decoratedname, unsigned int stub_index)
+{
+  char buf[300];
+
+  fprintf(stubs_out, ".globl _%s\n", decoratedname);
+  fprintf(stubs_out, "_%s:\n", decoratedname);
+  fprintf(stubs_out, "  pushl $%d\n", stub_index);
+  fprintf(stubs_out, "  jmp passthrough\n");
+  fprintf(stubs_out, "\n");
+
+  fprintf(hooks_out, "  {\"%s\", \"%s\", NULL, NULL},\n",
+    dllname, get_undecorate_name(buf, decoratedname));
+}
+
+void
+create_stubs_and_hooks(
+  FILE *in,
+  FILE *stubs_out,
+  FILE *hooks_out)
+{
+  char line[INPUT_BUFFER_SIZE];
+  char *s;
+  char *dllname;
+  char *decoratedname;
+  int stub_index;
+
+  write_stubs_header(stubs_out);
+
+  write_hooks_header(hooks_out);
+
+       /*
+        * Scan the database. The database is a text file; each
+   * line is a record, which contains data for one stub.
+        * Each record has two columns:
+        *
+        * DLLNAME (e.g. ntdll.dll)
+        * DECORATED NAME (e.g. NtCreateProcess@32, @InterlockedIncrement@4 or printf)
+        */
+       for (
+    /* First stub has index zero */
+               stub_index = 0;
+               /* Go on until EOF or read zero bytes */
+               ((!feof(in)) && (fgets(line, sizeof line, in) != NULL));
+               /* Next stub index */
+         stub_index++)
+       {
+               /*
+                * Remove, if present, the trailing CR.
+                * (os specific?)
+                */
+               if ((s = (char *) strchr(line,'\r')) != NULL)
+                 {
+                         *s = '\0';
+           }
+
+               /*
+                * Skip comments (#) and empty lines.
+                */
+               s = & line[0];
+               if ((*s) != '#' && (*s) != '\0')
+               {
+                       /* Extract the DLL name */
+                       dllname = (char *) strtok(s," \t");
+                       /* Extract the decorated function name */
+                       decoratedname = (char *) strtok(NULL," \t");
+                       /* Extract the argument count */
+                       write_stub(stubs_out, hooks_out, dllname, decoratedname, stub_index);
+               }
+       }
+
+  write_hooks_footer(hooks_out, stub_index + 1);
+}
+
+int run_stubs(int argc,
+  char **argv)
+{
+  FILE *in;
+  FILE *stubs_out;
+  FILE *hooks_out;
+
+       in = fopen(argv[2], "rb");
+       if (in == NULL)
+       {
+               perror("Failed to open stub description input file");
+               return 1;
+       }
+
+       stubs_out = fopen(argv[3], "wb");
+       if (stubs_out == NULL)
+       {
+               perror("Failed to open stubs output file");
+               return 1;
+       }
+
+       hooks_out = fopen(argv[4], "wb");
+       if (hooks_out == NULL)
+       {
+               perror("Failed to open hooks output file");
+               return 1;
+       }
+
+  create_stubs_and_hooks(in, stubs_out, hooks_out);
+
+  fclose(stubs_out);
+  fclose(hooks_out);
+
+  return 0;
+}
+
+int run_registrations(int argc,
   char **argv)
 {
   char buf[MAX_PATH];
@@ -578,7 +769,6 @@ int main(int argc,
     return 1;
   }
 
-
   strcpy(buf, convert_path(argv[1]));
   if (buf[strlen(buf)] != DIR_SEPARATOR_CHAR)
     {
@@ -728,3 +918,22 @@ int main(int argc,
 
   return 0;
 }
+
+int main(int argc,
+  char **argv)
+{
+  if (argc < 2)
+  {
+    puts(HELP);
+    return 1;
+  }
+
+  if (strlen(argv[1]) > 1 && argv[1][0] == '-' && argv[1][1] == 's')
+    {
+      return run_stubs(argc, argv);
+    }
+  else
+    {
+      return run_registrations(argc, argv);
+    }
+}