1b3f9618d9ed8f8e4524d12cbd8567c23d772269
2 * FILE: tools/nci/ncitool.c
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: Native Call Interface Support Tool
5 * PURPOSE: Generates NCI Tables and Stubs.
6 * PROGRAMMER; Alex Ionescu (alex@relsoft.net)
7 * CHANGE HISTORY: 14/01/05 - Created. Based on original code by
8 * KJK::Hyperion and Emanuelle Aliberti.
12 /* INCLUDE ******************************************************************/
19 /* DEFINES ****************************************************************/
21 #define INPUT_BUFFER_SIZE 255
24 /******* Table Indexes ************/
25 #define MAIN_INDEX 0x0
26 #define WIN32K_INDEX 0x1000
28 /******* Argument List ************/
29 /* First, define the Databases */
30 #define NativeSystemDb 0
33 /* Now the Service Tables */
34 #define NtosServiceTable 2
35 #define Win32kServiceTable 3
37 /* And finally, the stub files. */
38 #define NtosUserStubs 4
39 #define NtosKernelStubs 5
40 #define Win32kGdiStubs 6
41 #define Win32kUserStubs 7
43 /********** Stub Code ************/
46 * This stubs calls into KUSER_SHARED_DATA where either a
47 * sysenter or interrupt is performed, depending on CPU support.
50 #define UserModeStub_x86 " movl $0x%x, %%eax\n" \
51 " movl $KUSER_SHARED_SYSCALL, %%ecx\n" \
54 #elif defined(_MSC_VER)
55 #define UserModeStub_x86 " asm { \n" \
57 " mov ecx, KUSER_SHARED_SYSCALL\n" \
62 #error Unknown compiler for inline assembler
66 * This stub calls KiSystemService directly with a fake INT2E stack.
67 * Because EIP is pushed during the call, the handler will return here.
70 #define KernelModeStub_x86 " movl $0x%x, %%eax\n" \
71 " leal 4(%%esp), %%edx\n" \
73 " pushl $KERNEL_CS\n" \
74 " call _KiSystemService\n" \
76 #elif defined(_MSC_VER)
77 #define KernelModeStub_x86 " asm { \n" \
79 " lea edx, [esp+4]\n" \
82 " call _KiSystemService\n" \
86 #error Unknown compiler for inline assembler
89 /***** Arch Dependent Stuff ******/
91 #define ARGS_TO_BYTES(x) x*4
92 #define UserModeStub UserModeStub_x86
93 #define KernelModeStub KernelModeStub_x86
96 //#error Unsupported Architecture
99 /* FUNCTIONS ****************************************************************/
104 * Prints out the File Header for a Stub File.
107 * StubFile - Stub File to which to write the header.
109 * FileDescription - Description of the Stub file to which to write the header.
111 * FileLocation - Name of the Stub file to which to write the header.
117 * FileLocation is only used for printing the header.
121 WriteFileHeader(FILE * StubFile
,
122 char* FileDescription
,
125 /* This prints out the file header */
128 " * COPYRIGHT: See COPYING in the top level directory\n"
130 " * PROGRAMMER: Computer Generated File. See tools/nci/ncitool.c\n"
131 " * REMARK: DO NOT EDIT OR COMMIT MODIFICATIONS TO THIS FILE\n"
133 "#define KUSER_SHARED_SYSCALL 0x7FFE0300\n\n",
141 * Prints out the File Header for a Stub File.
144 * StubFile - Stub File to which to write the header.
146 * FileDescription - Description of the Stub file to which to write the header.
148 * FileLocation - Name of the Stub file to which to write the header.
154 * FileLocation is only used for printing the header.
158 WriteStubHeader(FILE* StubFile
,
162 /* Export the function */
163 fprintf(StubFile
, ".global _%s@%d\n", SyscallName
, StackBytes
);
166 fprintf(StubFile
, "_%s@%d:\n\n", SyscallName
, StackBytes
);
171 * WriteKernelModeStub
173 * Prints out the Kernel Mode Stub for a System Call.
176 * StubFile - Stub File to which to write the header.
178 * SyscallName - Name of System Call for which to add the stub.
180 * StackBytes - Number of bytes on the stack to return after doing the system call.
182 * SyscallId - Service Descriptor Table ID for this System Call.
188 * On i386, StackBytes is the number of arguments x 4.
192 WriteKernelModeStub(FILE* StubFile
,
195 unsigned int SyscallId
)
197 /* Write the Stub Header and export the Function */
198 WriteStubHeader(StubFile
, SyscallName
, StackBytes
);
200 /* Write the Stub Code */
201 fprintf(StubFile
, KernelModeStub
, SyscallId
, StackBytes
);
207 * Prints out the User Mode Stub for a System Call.
210 * StubFile - Stub File to which to write the header.
212 * SyscallName - Name of System Call for which to add the stub.
214 * StackBytes - Number of bytes on the stack to return after doing the system call.
216 * SyscallId - Service Descriptor Table ID for this System Call.
222 * On i386, StackBytes is the number of arguments x 4.
226 WriteUserModeStub(FILE* StubFile
,
229 unsigned int SyscallId
)
231 /* Write the Stub Header and export the Function */
232 WriteStubHeader(StubFile
, SyscallName
, StackBytes
);
234 /* Write the Stub Code */
235 fprintf(StubFile
, UserModeStub
, SyscallId
, StackBytes
);
239 * GetNameAndArgumentsFromDb
241 * Parses an entry from a System Call Database, extracting
242 * the function's name and arguments that it takes.
245 * Line - Entry from the Database to parse.
247 * NtSyscallName - Output string to which to save the Function Name
249 * SyscallArguments - Output string to which to save the number of
250 * arguments that the function takes.
256 * On i386, StackBytes is the number of arguments x 4.
260 GetNameAndArgumentsFromDb(char Line
[],
261 char ** NtSyscallName
,
262 char ** SyscallArguments
)
267 /* Remove new line */
268 if ((s
= (char *) strchr(Line
,'\r')) != NULL
) {
272 /* Skip comments (#) and empty lines */
274 if ((*s
) != '#' && (*s
) != '\0') {
276 /* Extract the NtXXX name */
277 *NtSyscallName
= (char *)strtok(s
," \t");
279 /* Extract the argument count */
280 *SyscallArguments
= (char *)strtok(NULL
," \t");
282 /* Remove, if present, the trailing LF */
283 if ((stmp
= strchr(*SyscallArguments
, '\n')) != NULL
) {
289 /* Skip this entry */
290 *NtSyscallName
= NULL
;
297 * Parses a System Call Database and creates stubs for all the entries.
300 * SyscallDb - System Call Database to parse.
302 * UserModeFiles - Array of Usermode Stub Files to which to write the stubs.
304 * KernelModeFile - Kernelmode Stub Files to which to write the stubs.
306 * Index - Name of System Call for which to add the stub.
308 * UserFiles - Number of bytes on the stack to return after doing the system call.
310 * NeedsZw - Service Descriptor Table ID for this System Call.
320 CreateStubs(FILE * SyscallDb
,
321 FILE * UserModeFiles
[],
322 FILE * KernelModeFile
,
327 char Line
[INPUT_BUFFER_SIZE
];
329 char *ZwSyscallName
= NULL
;
330 char *SyscallArguments
;
334 /* We loop, incrementing the System Call Index, until the end of the file */
335 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
337 /* Extract the Name and Arguments */
338 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
339 StackBytes
= ARGS_TO_BYTES(strtoul(SyscallArguments
, NULL
, 0));
341 /* Make sure we really extracted something */
344 /* Create the ZwXXX name, if requested */
346 ZwSyscallName
= alloca(strlen(NtSyscallName
));
347 strcpy(ZwSyscallName
, NtSyscallName
);
348 ZwSyscallName
[0] = 'Z';
349 ZwSyscallName
[1] = 'w';
352 /* Create Usermode Stubs for Nt/Zw syscalls in each Usermode file */
354 for (i
= 0; i
< UserFiles
; i
++) {
356 /* Write the Nt Version */
357 WriteUserModeStub(UserModeFiles
[i
],
362 /* If a Zw Version is needed (was specified), write it too */
363 if (ZwSyscallName
) WriteUserModeStub(UserModeFiles
[i
],
370 /* Create the Kernel coutnerparts (only Zw*, Nt* are the real functions!) */
371 if (KernelModeFile
) WriteKernelModeStub(KernelModeFile
,
376 /* Only increase if we actually added something */
383 * CreateSystemServiceTable
385 * Parses a System Call Database and creates a System Call Service Table for it.
388 * SyscallDb - System Call Database to parse.
390 * SyscallTable - File in where to create System Call Service Table.
392 * Name - Name of the Service Table.
394 * FileLocation - Filename containing the Table.
400 * FileLocation is only used for the header generation.
404 CreateSystemServiceTable(FILE *SyscallDb
,
409 char Line
[INPUT_BUFFER_SIZE
];
411 char *SyscallArguments
;
414 /* Print the Header */
415 WriteFileHeader(SyscallTable
, "System Call Table for Native API", FileLocation
);
417 /* First we build the SSDT */
418 fprintf(SyscallTable
,"\n\n\n");
419 fprintf(SyscallTable
,"SSDT %sSSDT[] = {\n", Name
);
421 /* We loop, incrementing the System Call Index, until the end of the file */
422 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
424 /* Extract the Name and Arguments */
425 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
427 /* Make sure we really extracted something */
431 if (SyscallId
> 0) fprintf(SyscallTable
,",\n");
433 /* Write the syscall name in the service table. */
434 fprintf(SyscallTable
,"\t\t(PVOID (NTAPI *)(VOID))%s", NtSyscallName
);
436 /* Only increase if we actually added something */
441 /* Close the service table (C syntax) */
442 fprintf(SyscallTable
,"\n};\n");
444 /* Now we build the SSPT */
446 fprintf(SyscallTable
,"\n\n\n");
447 fprintf(SyscallTable
,"SSPT %sSSPT[] = {\n", Name
);
449 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
451 /* Extract the Name and Arguments */
452 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
454 /* Make sure we really extracted something */
458 if (SyscallId
> 0) fprintf(SyscallTable
,",\n");
460 /* Write the syscall arguments in the argument table. */
461 fprintf(SyscallTable
,"\t\t%lu * sizeof(void *)",strtoul(SyscallArguments
, NULL
, 0));
463 /* Only increase if we actually added something */
468 /* Close the service table (C syntax) */
469 fprintf(SyscallTable
,"\n};\n");
472 * We write some useful defines
474 fprintf(SyscallTable
, "\n\n#define MIN_SYSCALL_NUMBER 0\n");
475 fprintf(SyscallTable
, "#define MAX_SYSCALL_NUMBER %d\n", SyscallId
- 1);
476 fprintf(SyscallTable
, "#define NUMBER_OF_SYSCALLS %d\n", SyscallId
);
477 fprintf(SyscallTable
, "ULONG %sNumberOfSysCalls = %d;\n", Name
, SyscallId
);
480 void usage(char * argv0
)
482 printf("Usage: %s sysfuncs.lst w32ksvc.db napi.h ssdt.h napi.S zw.S win32k.S win32k.S\n"
483 " sysfuncs.lst native system functions database\n"
484 " w32ksvc.db native graphic functions database\n"
485 " napi.h NTOSKRNL service table\n"
486 " ssdt.h WIN32K service table\n"
487 " napi.S NTDLL stubs\n"
488 " zw.S NTOSKRNL Zw stubs\n"
489 " win32k.S GDI32 stubs\n"
490 " win32k.S USER32 stubs\n",
495 int main(int argc
, char* argv
[])
497 FILE * Files
[Arguments
];
499 char * OpenType
= "r";
501 /* Make sure all arguments all there */
502 if (argc
!= Arguments
+ 1) {
507 /* Open all Output and bail out if any fail */
508 for (FileNumber
= 0; FileNumber
< Arguments
; FileNumber
++) {
511 if (FileNumber
== 2) OpenType
= "wb";
512 Files
[FileNumber
] = fopen(argv
[FileNumber
+ 1], OpenType
);
514 /* Check for failure and error out if so */
515 if (!Files
[FileNumber
]) {
516 perror(argv
[FileNumber
+ 1]);
522 /* Write the File Headers */
523 WriteFileHeader(Files
[NtosUserStubs
],
524 "System Call Stubs for Native API",
525 argv
[NtosUserStubs
+ 1]);
527 WriteFileHeader(Files
[NtosKernelStubs
],
528 "System Call Stubs for Native API",
529 argv
[NtosKernelStubs
+ 1]);
530 fputs("#include <ndk/i386/segment.h>\n\n", Files
[NtosKernelStubs
]);
532 WriteFileHeader(Files
[Win32kGdiStubs
],
533 "System Call Stubs for Native API",
534 argv
[Win32kGdiStubs
+ 1]);
536 WriteFileHeader(Files
[Win32kUserStubs
],
537 "System Call Stubs for Native API",
538 argv
[Win32kUserStubs
+ 1]);
541 /* Create the System Stubs */
542 CreateStubs(Files
[NativeSystemDb
],
543 &Files
[NtosUserStubs
],
544 Files
[NtosKernelStubs
],
549 /* Create the Graphics Stubs */
550 CreateStubs(Files
[NativeGuiDb
],
551 &Files
[Win32kGdiStubs
],
557 /* Rewind the databases */
558 rewind(Files
[NativeSystemDb
]);
559 rewind(Files
[NativeGuiDb
]);
561 /* Create the Service Tables */
562 CreateSystemServiceTable(Files
[NativeSystemDb
],
563 Files
[NtosServiceTable
],
565 argv
[NtosServiceTable
+ 1]);
567 CreateSystemServiceTable(Files
[NativeGuiDb
],
568 Files
[Win32kServiceTable
],
570 argv
[Win32kServiceTable
+ 1]);
572 /* Close all files */
573 for (FileNumber
= 0; FileNumber
< Arguments
; FileNumber
++) {
576 fclose(Files
[FileNumber
]);