#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#ifdef WIN32
#include <io.h>
#include <dirent.h>
#include <unistd.h>
#endif
-#include <ctype.h>
-#ifndef WIN32
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
+#ifndef WIN32
#define DIR_SEPARATOR_CHAR '/'
#define DIR_SEPARATOR_STRING "/"
#else
static char *path;
static char *file;
static char *makefile;
-static char *umstubfile;
-static char *kmstubfile;
+static char *exestubfile;
-char* convert_path(char* origpath)
+static char*
+convert_path(char* origpath)
{
char* newpath;
int i;
return(newpath);
}
-static void write_line(char *line)
+static void
+write_line(char *line)
{
int n_out;
char buf[200];
n_out = fwrite(&buf[0], 1, strlen(buf), out);
}
-static void change_extension(char *filenamebuffer, char *filename, char *newextension)
+static void
+change_extension(char *filenamebuffer,
+ char *filename,
+ char *newextension)
{
char *ptr;
}
}
+static void
+get_test_name(char *filename,
+ char *testname)
+{
+ int i;
+
+ strcpy(testname, filename);
+
+ i = strlen(testname);
+ while (i > 0 && testname[i] != '.')
+ {
+ i--;
+ }
+ if (i > 0)
+ {
+ testname[i] = 0;
+ }
+
+ /* Make a capital first letter and make all other letters lower case */
+ testname[0] = toupper(testname[0]);
+ if (!((testname[0] >= 'A' && testname[0] <= 'Z') ||
+ (testname[0] >= '0' && testname[0] <= '9')))
+ {
+ testname[0] = '_';
+ }
+ i = 1;
+ while (i < strlen(testname))
+ {
+ testname[i] = tolower(testname[i]);
+ if (!((testname[i] >= 'a' && testname[i] <= 'z') ||
+ (testname[i] >= '0' && testname[i] <= '9')))
+ {
+ testname[i] = '_';
+ }
+ i++;
+ }
+}
+
/*
* filename - name of file to make registrations for
- * regtype - type of registration (0 = prototype, 1 = call, 2 = makefile)
+ * type - type of registration (0 = prototype, 1 = call, 2 = makefile)
*/
-void register_test(char *filename, int type)
+static void
+register_test(char *filename,
+ int type)
{
char ext[100];
char testname[100];
char call[100];
char regtest[100];
char filenamebuffer[MAX_PATH];
- int i, j;
-
- strcpy(testname, filename);
+ int i;
- i = strlen(testname);
- while (i > 0 && testname[i] != '.')
+ i = strlen(filename);
+ while (i > 0 && filename[i] != '.')
{
i--;
}
if (i > 0)
{
memset(ext, 0, sizeof(ext));
- strncpy(&ext[0], &testname[i], strlen(&testname[i]));
+ strncpy(&ext[0], &filename[i], strlen(&filename[i]));
if ((strncmp(ext, ".c", 2) != 0) && (strncmp(ext, ".C", 2) != 0))
{
return;
}
-
- testname[i] = 0;
}
else
{
return;
}
- // Make a capital first letter and make all other letters lower case
- testname[0] = toupper(testname[0]);
- if (!((testname[0] >= 'A' && testname[0] <= 'Z') ||
- (testname[0] >= '0' && testname[0] <= '9')))
- {
- testname[0] = '_';
- }
- j = 1;
- while (j < strlen(testname))
- {
- testname[j] = tolower(testname[j]);
- if (!((testname[j] >= 'a' && testname[j] <= 'z') ||
- (testname[j] >= '0' && testname[j] <= '9')))
- {
- testname[j] = '_';
- }
- j++;
- }
+ memset(testname, 0, sizeof(testname));
+ get_test_name(filename, testname);
if (type == 0)
{
#endif
static int
-is_file_changed(char *filename, char *content)
+is_file_changed(char *filename,
+ char *content)
{
FILE *file;
int size;
}
static int
-write_file_if_changed(char *filename, char *content)
+write_file_if_changed(char *filename,
+ char *content)
{
FILE *file;
int n;
return 0;
}
-static char KMSTUB[] =
+static char EXESTUB[] =
"/* This file is autogenerated. */\n"
"\n"
- "#include <roskrnl.h>\n"
- "#include <../kmregtests/kmregtests.h>\n"
- "\n"
- "typedef int (*TestRoutine)(int Command, char *Buffer);\n"
- "\n"
- "extern void RegisterTests();\n"
- "\n"
- "static PDEVICE_OBJECT KMRegTestsDeviceObject = NULL;\n"
- "static PFILE_OBJECT KMRegTestsFileObject = NULL;\n"
+ "#include \"regtests.h\"\n"
"\n"
- "void AddTest(TestRoutine Routine)\n"
+ "void\n"
+ "ConsoleWrite(char *Buffer)\n"
"{\n"
- " PDEVICE_OBJECT DeviceObject;\n"
- " UNICODE_STRING DriverName;\n"
- " IO_STATUS_BLOCK IoStatus;\n"
- " NTSTATUS Status;\n"
- " KEVENT Event;\n"
- " PIRP Irp;\n"
- "\n"
- " if (KMRegTestsDeviceObject == NULL)\n"
- " {\n"
- " RtlInitUnicodeString(&DriverName, L\"\\\\Device\\\\KMRegTests\");\n"
- " Status = IoGetDeviceObjectPointer(&DriverName, FILE_WRITE_ATTRIBUTES,\n"
- " &KMRegTestsFileObject, &KMRegTestsDeviceObject);\n"
- " if (!NT_SUCCESS(Status)) return;\n"
- " }\n"
- " KeInitializeEvent(&Event, NotificationEvent, FALSE);\n"
- " Irp = IoBuildDeviceIoControlRequest(IOCTL_KMREGTESTS_REGISTER,\n"
- " KMRegTestsDeviceObject, &Routine, sizeof(TestRoutine), NULL, 0, FALSE, &Event, &IoStatus);\n"
- " Status = IoCallDriver(KMRegTestsDeviceObject, Irp);\n"
+ " printf(Buffer);\n"
"}\n"
"\n"
- "void PrepareTests()\n"
+ "int\n"
+ "mainCRTStartup(HANDLE hInstance,\n"
+ " HANDLE hPrevInstance,\n"
+ " LPSTR lpszCmdParam,\n"
+ " int nCmdShow)\n"
"{\n"
+ " InitializeTests();\n"
" RegisterTests();\n"
+ " SetupOnce();\n"
+ " PerformTests(ConsoleWrite, NULL);\n"
+ " _ExitProcess(0);\n"
+ " return 0;\n"
"}\n";
-static char UMSTUB[] =
+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"
- "\n"
"#include <windows.h>\n"
- "#define NTOS_MODE_USER\n"
- "#include <ntos.h>\n"
"#include \"regtests.h\"\n"
"\n"
- "PVOID\n"
- "AllocateMemory(ULONG Size)\n"
- "{\n"
- " return (PVOID) RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);\n"
- "}\n"
- "\n"
- "VOID\n"
- "FreeMemory(PVOID Base)\n"
- "{\n"
- " RtlFreeHeap(RtlGetProcessHeap(), 0, Base);\n"
- "}\n"
+ "API_DESCRIPTION ExternalDependencies[] =\n"
+ "{\n";
+
+static char HOOKS_FOOTER[] =
+ "};\n"
"\n"
- "/* This function will be called several times */\n"
- "void PrepareTests()\n"
- "{\n"
- " static int testsRegistered = 0;\n"
- " if (testsRegistered == 0)\n"
- " {\n"
- " HANDLE hEvent;\n"
- " hEvent = OpenEventW(\n"
- " EVENT_ALL_ACCESS,\n"
- " FALSE,\n"
- " L\"WinRegTests\");\n"
- " if (hEvent != NULL)\n"
- " {\n"
- " SetEvent(hEvent);\n"
- " CloseHandle(hEvent);\n"
- " testsRegistered = 1;\n"
- " InitializeTests();\n"
- " RegisterTests();\n"
- " PerformTests();\n"
- " }\n"
- " }\n"
- "}\n";
+ "#define ExternalDependencyCount %d\n"
+ "ULONG MaxExternalDependency = ExternalDependencyCount - 1;\n";
static char HELP[] =
- "REGTESTS path file makefile [-u umstubfile] [-k kmstubfile]\n"
+ "REGTESTS path file makefile [-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";
+ " path Path to files\n"
+ " file Registration file to create\n"
+ " makefile Makefile to create\n"
+ " exestubfile Optional stub for running tests 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, char **argv)
+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_symbolname(char *decoratedname)
+{
+ char buf[300];
+
+ if (decoratedname[0] == '@')
+ return strdup(decoratedname);
+ strcpy(buf, "_");
+ strcat(buf, decoratedname);
+ return strdup(buf);
+}
+
+char *
+get_undecorated_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;
+}
+
+char *
+get_forwarded_export(char *forwardedexport)
+{
+ char buf[300];
+
+ if (forwardedexport == NULL)
+ {
+ strcpy(buf, "NULL");
+ }
+ else
+ {
+ sprintf(buf, "\"%s\"", forwardedexport);
+ }
+ return strdup(buf);
+}
+
+void
+write_stub(FILE *stubs_out, FILE *hooks_out, char *dllname,
+ char *decoratedname_and_forward, unsigned int stub_index)
+{
+ char buf[300];
+ char *p;
+ char *decoratedname = NULL;
+ char *forwardedexport = NULL;
+ char *symbolname = NULL;
+
+ p = strtok(decoratedname_and_forward, "=");
+ if (p != NULL)
+ {
+ decoratedname = p;
+
+ p = strtok(NULL, "=");
+ forwardedexport = p;
+ }
+ else
+ {
+ decoratedname = decoratedname_and_forward;
+ forwardedexport = decoratedname_and_forward;
+ }
+
+ symbolname = get_symbolname(decoratedname);
+ fprintf(stubs_out, ".globl %s\n", symbolname);
+ fprintf(stubs_out, "%s:\n", symbolname);
+ free(symbolname);
+ fprintf(stubs_out, " pushl $%d\n", stub_index);
+ fprintf(stubs_out, " jmp passthrough\n");
+ fprintf(stubs_out, "\n");
+ forwardedexport = get_forwarded_export(forwardedexport);
+ fprintf(hooks_out, " {\"%s\", \"%s\", %s, NULL, NULL},\n",
+ dllname,
+ get_undecorated_name(buf, decoratedname),
+ forwardedexport);
+ free(forwardedexport);
+}
+
+void
+create_stubs_and_hooks(
+ FILE *in,
+ FILE *stubs_out,
+ FILE *hooks_out)
+{
+ char line[INPUT_BUFFER_SIZE];
+ char *s;
+ char *dllname;
+ char *decoratedname_and_forward;
+ 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)
+ */
+ stub_index = 0; /* First stub has index zero */
+
+ for (
+ ;
+ /* Go on until EOF or read zero bytes */
+ ((!feof(in)) && (fgets(line, sizeof line, in) != NULL));
+ /* Next stub index */
+ )
+ {
+ /*
+ * Remove, if present, the trailing LF.
+ */
+ if ((s = (char *) strchr(line,'\n')) != NULL)
+ {
+ *s = '\0';
+ }
+
+ /*
+ * Remove, if present, the trailing CR.
+ */
+ 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");
+ if (dllname != NULL && strlen(dllname) > 0)
+ {
+ /*
+ * Extract the decorated function name and possibly forwarded export.
+ * Format:
+ * decoratedname=forwardedexport (no DLL name)
+ */
+ decoratedname_and_forward = (char *) strtok(NULL, " \t");
+ /* Extract the argument count */
+ write_stub(stubs_out, hooks_out, dllname, decoratedname_and_forward, stub_index);
+ stub_index++;
+ }
+ }
+ }
+
+ write_hooks_footer(hooks_out, stub_index);
+}
+
+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];
int i;
return 1;
}
-
strcpy(buf, convert_path(argv[1]));
if (buf[strlen(buf)] != DIR_SEPARATOR_CHAR)
{
return 1;
}
- umstubfile = NULL;
- kmstubfile = NULL;
+ exestubfile = NULL;
for (i = 4; i < argc; i++)
{
if (argv[i][0] == '-')
{
- if (argv[i][1] == 'u')
- {
- umstubfile = convert_path(argv[++i]);
- if (umstubfile[0] == 0)
- {
- printf("Missing umstubfile\n");
- return 1;
- }
- }
- else if (argv[i][1] == 'k')
- {
- kmstubfile = convert_path(argv[++i]);
- if (kmstubfile[0] == 0)
- {
- printf("Missing kmstubfile\n");
- return 1;
- }
- }
- else
- {
- printf("Unknown switch\n");
- return 1;
- }
+ if (argv[i][1] == 'e')
+ {
+ exestubfile = convert_path(argv[++i]);
+ if (exestubfile[0] == 0)
+ {
+ printf("Missing exestubfile\n");
+ return 1;
+ }
+ }
+ else
+ {
+ printf("Unknown switch -%c\n", argv[i][1]);
+ return 1;
+ }
}
}
fclose(out);
- /* User-mode stubfile */
- if (umstubfile != NULL)
+ /* Executable stubfile */
+ if (exestubfile != NULL)
{
- if (write_file_if_changed(umstubfile, UMSTUB) != 0)
- {
- perror("Cannot create output user-mode stubfile");
+ if (write_file_if_changed(exestubfile, EXESTUB) != 0)
+ {
+ perror("Cannot create output executable stubfile");
return 1;
}
}
- /* Kernel-mode stubfile */
- if (kmstubfile != NULL)
- {
- if (write_file_if_changed(kmstubfile, KMSTUB) != 0)
- {
- perror("Cannot create output kernel-mode stubfile");
- return 1;
- }
- }
+ return 0;
+}
- printf("Successfully generated regression test registrations.\n");
+int main(int argc,
+ char **argv)
+{
+ if (argc < 2)
+ {
+ puts(HELP);
+ return 1;
+ }
- return 0;
+ if (strlen(argv[1]) > 1 && argv[1][0] == '-' && argv[1][1] == 's')
+ {
+ return run_stubs(argc, argv);
+ }
+ else
+ {
+ return run_registrations(argc, argv);
+ }
}