mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 17:44:45 +00:00
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. svn path=/trunk/; revision=11147
This commit is contained in:
parent
d12bb0393c
commit
9495493fde
9 changed files with 371 additions and 62 deletions
|
@ -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.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
_hooks.c
|
||||
_regtests.c
|
||||
_rtstub.c
|
||||
_stubs.S
|
||||
Makefile.tests
|
||||
*.d
|
||||
*.o
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
3
reactos/lib/gdiplus/tests/stubs.tst
Normal file
3
reactos/lib/gdiplus/tests/stubs.tst
Normal file
|
@ -0,0 +1,3 @@
|
|||
ntdll.dll RtlAllocateHeap@12
|
||||
ntdll.dll RtlFreeHeap@12
|
||||
msvcrt.dll printf
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
||||
int main(int argc,
|
||||
#define INPUT_BUFFER_SIZE 255
|
||||
|
||||
void
|
||||
write_stubs_header(FILE * out)
|
||||
{
|
||||
fputs(STUBS_HEADER, out);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue