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 ******************************************************************/
17 #if !defined(__FreeBSD__) && !defined(__APPLE__)
21 /* DEFINES ****************************************************************/
23 #define INPUT_BUFFER_SIZE 255
26 /******* Table Indexes ************/
27 #define MAIN_INDEX 0x0
28 #define WIN32K_INDEX 0x1000
30 /******* Argument List ************/
31 /* First, define the Databases */
32 #define NativeSystemDb 0
35 /* Now the Service Tables */
36 #define NtosServiceTable 2
37 #define Win32kServiceTable 3
39 /* And finally, the stub files. */
40 #define NtosUserStubs 4
41 #define NtosKernelStubs 5
44 /********** Stub Code ************/
47 * This stubs calls into KUSER_SHARED_DATA where either a
48 * sysenter or interrupt is performed, depending on CPU support.
51 #define UserModeStub_x86 " movl $0x%x, %%eax\n" \
52 " movl $KUSER_SHARED_SYSCALL, %%ecx\n" \
56 #define UserModeStub_ppc " stwu 1,-16(1)\n" \
66 #define UserModeStub_mips " li $8, KUSER_SHARED_SYSCALL\n" \
72 // For now, only supports 0-4 arguments
74 #define UserModeStub_arm " ldr r12, =%x\n" \
78 #elif defined(_MSC_VER)
79 #define UserModeStub_x86 " asm { \n" \
81 " mov ecx, KUSER_SHARED_SYSCALL\n" \
86 #error Unknown compiler for inline assembler
90 * This stub calls KiSystemService directly with a fake INT2E stack.
91 * Because EIP is pushed during the call, the handler will return here.
94 #define KernelModeStub_x86 " movl $0x%x, %%eax\n" \
95 " leal 4(%%esp), %%edx\n" \
97 " pushl $KGDT_R0_CODE\n" \
98 " call _KiSystemService\n" \
101 /* For now, use the usermode stub. We'll optimize later */
102 #define KernelModeStub_ppc UserModeStub_ppc
104 #define KernelModeStub_mips " j KiSystemService\n" \
107 #define KernelModeStub_arm " ldr r12, =x%x\n" \
111 #elif defined(_MSC_VER)
112 #define KernelModeStub_x86 " asm { \n" \
114 " lea edx, [esp+4]\n" \
116 " push KGDT_R0_CODE\n" \
117 " call _KiSystemService\n" \
121 #error Unknown compiler for inline assembler
124 /***** Arch Dependent Stuff ******/
125 struct ncitool_data_t
{
130 const char *global_header
;
131 const char *declaration
;
134 struct ncitool_data_t ncitool_data
[] = {
135 { "i386", 4, KernelModeStub_x86
, UserModeStub_x86
,
136 ".global _%s@%d\n", "_%s@%d:\n" },
137 { "powerpc", 4, KernelModeStub_ppc
, UserModeStub_ppc
,
138 "\t.globl %s\n", "%s:\n" },
139 { "mips", 4, KernelModeStub_mips
, UserModeStub_mips
,
140 "\t.globl %s\n", "%s:\n" },
141 { "arm", 4, KernelModeStub_arm
, UserModeStub_arm
,
142 "\t.globl %s\n", "%s:\n" },
146 #define ARGS_TO_BYTES(x) (x)*(ncitool_data[arch_sel].args_to_bytes)
147 #define UserModeStub ncitool_data[arch_sel].um_stub
148 #define KernelModeStub ncitool_data[arch_sel].km_stub
149 #define GlobalHeader ncitool_data[arch_sel].global_header
150 #define Declaration ncitool_data[arch_sel].declaration
152 /* FUNCTIONS ****************************************************************/
157 * Prints out the File Header for a Stub File.
160 * StubFile - Stub File to which to write the header.
162 * FileDescription - Description of the Stub file to which to write the header.
164 * FileLocation - Name of the Stub file to which to write the header.
170 * FileLocation is only used for printing the header.
174 WriteFileHeader(FILE * StubFile
,
175 char* FileDescription
,
178 /* This prints out the file header */
181 " * COPYRIGHT: See COPYING in the top level directory\n"
183 " * PROGRAMMER: Computer Generated File. See tools/nci/ncitool.c\n"
184 " * REMARK: DO NOT EDIT OR COMMIT MODIFICATIONS TO THIS FILE\n"
186 "#include <ndk/asm.h>\n\n",
194 * Prints out the File Header for a Stub File.
197 * StubFile - Stub File to which to write the header.
199 * FileDescription - Description of the Stub file to which to write the header.
201 * FileLocation - Name of the Stub file to which to write the header.
207 * FileLocation is only used for printing the header.
211 WriteStubHeader(FILE* StubFile
,
215 /* Export the function */
216 fprintf(StubFile
, GlobalHeader
, SyscallName
, StackBytes
);
219 fprintf(StubFile
, Declaration
, SyscallName
, StackBytes
);
224 * WriteKernelModeStub
226 * Prints out the Kernel Mode Stub for a System Call.
229 * StubFile - Stub File to which to write the header.
231 * SyscallName - Name of System Call for which to add the stub.
233 * StackBytes - Number of bytes on the stack to return after doing the system call.
235 * SyscallId - Service Descriptor Table ID for this System Call.
241 * On i386, StackBytes is the number of arguments x 4.
245 WriteKernelModeStub(FILE* StubFile
,
248 unsigned int SyscallId
)
250 /* Write the Stub Header and export the Function */
251 WriteStubHeader(StubFile
, SyscallName
, StackBytes
);
253 /* Write the Stub Code */
254 fprintf(StubFile
, KernelModeStub
, SyscallId
, StackBytes
);
260 * Prints out the User Mode Stub for a System Call.
263 * StubFile - Stub File to which to write the header.
265 * SyscallName - Name of System Call for which to add the stub.
267 * StackBytes - Number of bytes on the stack to return after doing the system call.
269 * SyscallId - Service Descriptor Table ID for this System Call.
275 * On i386, StackBytes is the number of arguments x 4.
279 WriteUserModeStub(FILE* StubFile
,
282 unsigned int SyscallId
)
284 /* Write the Stub Header and export the Function */
285 WriteStubHeader(StubFile
, SyscallName
, StackBytes
);
287 /* Write the Stub Code */
288 fprintf(StubFile
, UserModeStub
, SyscallId
, StackBytes
);
292 * GetNameAndArgumentsFromDb
294 * Parses an entry from a System Call Database, extracting
295 * the function's name and arguments that it takes.
298 * Line - Entry from the Database to parse.
300 * NtSyscallName - Output string to which to save the Function Name
302 * SyscallArguments - Output string to which to save the number of
303 * arguments that the function takes.
309 * On i386, StackBytes is the number of arguments x 4.
313 GetNameAndArgumentsFromDb(char Line
[],
314 char ** NtSyscallName
,
315 char ** SyscallArguments
)
320 /* Remove new line */
321 if ((s
= (char *) strchr(Line
,'\r')) != NULL
) {
325 /* Skip comments (#) and empty lines */
327 if ((*s
) != '#' && (*s
) != '\0') {
329 /* Extract the NtXXX name */
330 *NtSyscallName
= (char *)strtok(s
," \t");
332 /* Extract the argument count */
333 *SyscallArguments
= (char *)strtok(NULL
," \t");
335 /* Remove, if present, the trailing LF */
336 if ((stmp
= strchr(*SyscallArguments
, '\n')) != NULL
) {
342 /* Skip this entry */
343 *NtSyscallName
= NULL
;
344 *SyscallArguments
= NULL
;
351 * Parses a System Call Database and creates stubs for all the entries.
354 * SyscallDb - System Call Database to parse.
356 * UserModeFiles - Array of Usermode Stub Files to which to write the stubs.
358 * KernelModeFile - Kernelmode Stub Files to which to write the stubs.
360 * Index - Number of first syscall
362 * UserFiles - Number of Usermode Stub Files to create
364 * NeedsZw - Write Zw prefix?
374 CreateStubs(FILE * SyscallDb
,
375 FILE * UserModeFiles
[],
376 FILE * KernelModeFile
,
381 char Line
[INPUT_BUFFER_SIZE
];
383 char *SyscallArguments
;
387 /* We loop, incrementing the System Call Index, until the end of the file */
388 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
390 /* Extract the Name and Arguments */
391 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
392 if (SyscallArguments
!= NULL
)
393 StackBytes
= ARGS_TO_BYTES(strtoul(SyscallArguments
, NULL
, 0));
397 /* Make sure we really extracted something */
400 /* Create Usermode Stubs for Nt/Zw syscalls in each Usermode file */
402 for (i
= 0; i
< UserFiles
; i
++) {
404 /* Write the Nt Version */
405 WriteUserModeStub(UserModeFiles
[i
],
410 /* If a Zw Version is needed (was specified), write it too */
413 NtSyscallName
[0] = 'Z';
414 NtSyscallName
[1] = 'w';
415 WriteUserModeStub(UserModeFiles
[i
],
423 /* Create the Kernel coutnerparts (only Zw*, Nt* are the real functions!) */
424 if (KernelModeFile
) {
426 NtSyscallName
[0] = 'Z';
427 NtSyscallName
[1] = 'w';
428 WriteKernelModeStub(KernelModeFile
,
434 /* Only increase if we actually added something */
441 * CreateSystemServiceTable
443 * Parses a System Call Database and creates a System Call Service Table for it.
446 * SyscallDb - System Call Database to parse.
448 * SyscallTable - File in where to create System Call Service Table.
450 * Name - Name of the Service Table.
452 * FileLocation - Filename containing the Table.
458 * FileLocation is only used for the header generation.
462 CreateSystemServiceTable(FILE *SyscallDb
,
467 char Line
[INPUT_BUFFER_SIZE
];
469 char *SyscallArguments
;
472 /* Print the Header */
473 WriteFileHeader(SyscallTable
, "System Call Table for Native API", FileLocation
);
475 /* First we build the SSDT */
476 fprintf(SyscallTable
,"\n\n\n");
477 fprintf(SyscallTable
,"ULONG_PTR %sSSDT[] = {\n", Name
);
479 /* We loop, incrementing the System Call Index, until the end of the file */
480 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
482 /* Extract the Name and Arguments */
483 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
485 /* Make sure we really extracted something */
489 if (SyscallId
> 0) fprintf(SyscallTable
,",\n");
491 /* Write the syscall name in the service table. */
492 fprintf(SyscallTable
,"\t\t(ULONG_PTR)%s", NtSyscallName
);
494 /* Only increase if we actually added something */
499 /* Close the service table (C syntax) */
500 fprintf(SyscallTable
,"\n};\n");
502 /* Now we build the SSPT */
504 fprintf(SyscallTable
,"\n\n\n");
505 fprintf(SyscallTable
,"UCHAR %sSSPT[] = {\n", Name
);
507 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
509 /* Extract the Name and Arguments */
510 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
512 /* Make sure we really extracted something */
516 if (SyscallId
> 0) fprintf(SyscallTable
,",\n");
518 /* Write the syscall arguments in the argument table. */
519 if (SyscallArguments
!= NULL
)
520 fprintf(SyscallTable
,"\t\t%lu * sizeof(void *)",strtoul(SyscallArguments
, NULL
, 0));
522 fprintf(SyscallTable
,"\t\t0");
524 /* Only increase if we actually added something */
529 /* Close the service table (C syntax) */
530 fprintf(SyscallTable
,"\n};\n");
533 * We write some useful defines
535 fprintf(SyscallTable
, "\n\n#define MIN_SYSCALL_NUMBER 0\n");
536 fprintf(SyscallTable
, "#define MAX_SYSCALL_NUMBER %d\n", SyscallId
- 1);
537 fprintf(SyscallTable
, "#define NUMBER_OF_SYSCALLS %d\n", SyscallId
);
538 fprintf(SyscallTable
, "ULONG %sNumberOfSysCalls = %d;\n", Name
, SyscallId
);
541 void usage(char * argv0
)
543 printf("Usage: %s [-arch <arch>] sysfuncs.lst w32ksvc.db napi.h ssdt.h napi.S zw.S win32k.S win32k.S\n"
544 " sysfuncs.lst native system functions database\n"
545 " w32ksvc.db native graphic functions database\n"
546 " napi.h NTOSKRNL service table\n"
547 " ssdt.h WIN32K service table\n"
548 " napi.S NTDLL stubs\n"
549 " zw.S NTOSKRNL Zw stubs\n"
550 " win32k.S GDI32 stubs\n"
551 " win32k.S USER32 stubs\n"
552 " -arch is optional, default is %s\n",
558 int main(int argc
, char* argv
[])
560 FILE * Files
[Arguments
] = { };
561 int FileNumber
, ArgOffset
= 1;
562 char * OpenType
= "r";
564 /* Catch architecture argument */
565 if (argc
> 3 && !strcmp(argv
[1],"-arch")) {
566 for( arch_sel
= 0; ncitool_data
[arch_sel
].arch
; arch_sel
++ )
567 if (strcmp(argv
[2],ncitool_data
[arch_sel
].arch
) == 0)
569 if (!ncitool_data
[arch_sel
].arch
) {
570 printf("Invalid arch '%s'\n", argv
[2]);
576 /* Make sure all arguments all there */
577 if (argc
!= Arguments
+ ArgOffset
) {
582 /* Open all Output and bail out if any fail */
583 for (FileNumber
= 0; FileNumber
< Arguments
; FileNumber
++) {
586 if (FileNumber
== 2) OpenType
= "wb";
587 Files
[FileNumber
] = fopen(argv
[FileNumber
+ ArgOffset
], OpenType
);
589 /* Check for failure and error out if so */
590 if (!Files
[FileNumber
]) {
591 perror(argv
[FileNumber
+ ArgOffset
]);
596 /* Write the File Headers */
597 WriteFileHeader(Files
[NtosUserStubs
],
598 "System Call Stubs for Native API",
599 argv
[NtosUserStubs
+ ArgOffset
]);
601 WriteFileHeader(Files
[NtosKernelStubs
],
602 "System Call Stubs for Native API",
603 argv
[NtosKernelStubs
+ ArgOffset
]);
604 fputs("#include <ndk/asm.h>\n\n", Files
[NtosKernelStubs
]);
606 WriteFileHeader(Files
[Win32kStubs
],
607 "System Call Stubs for Native API",
608 argv
[Win32kStubs
+ ArgOffset
]);
610 /* Create the System Stubs */
611 CreateStubs(Files
[NativeSystemDb
],
612 &Files
[NtosUserStubs
],
613 Files
[NtosKernelStubs
],
618 /* Create the Graphics Stubs */
619 CreateStubs(Files
[NativeGuiDb
],
626 /* Rewind the databases */
627 rewind(Files
[NativeSystemDb
]);
628 rewind(Files
[NativeGuiDb
]);
630 /* Create the Service Tables */
631 CreateSystemServiceTable(Files
[NativeSystemDb
],
632 Files
[NtosServiceTable
],
634 argv
[NtosServiceTable
+ ArgOffset
]);
636 CreateSystemServiceTable(Files
[NativeGuiDb
],
637 Files
[Win32kServiceTable
],
639 argv
[Win32kServiceTable
+ ArgOffset
]);
641 /* Close all files */
642 for (FileNumber
= 0; FileNumber
< Arguments
-ArgOffset
; FileNumber
++) {
645 fclose(Files
[FileNumber
]);