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 ************/
32 #define NativeSystemDb 0
36 #define NtosServiceTable 2
37 #define Win32kServiceTable 3
40 #define NtosUserStubs 4
41 #define NtosKernelStubs 5
47 /********** Stub Code ************/
50 * This stubs calls into KUSER_SHARED_DATA where either a
51 * sysenter or interrupt is performed, depending on CPU support.
54 #define UserModeStub_x86 " movl $0x%x, %%eax\n" \
55 " movl $KUSER_SHARED_SYSCALL, %%ecx\n" \
59 #define UserModeStub_amd64 " movl $0x%x, %%eax\n" \
60 " movq %%rcx, %%r10\n" \
64 #define UserModeStub_ppc " stwu 1,-16(1)\n" \
74 #define UserModeStub_mips " li $8, KUSER_SHARED_SYSCALL\n" \
79 #define UserModeStub_arm " swi #0x%x\n" \
82 #elif defined(_MSC_VER)
83 #define UserModeStub_x86 " asm { \n" \
85 " mov ecx, KUSER_SHARED_SYSCALL\n" \
90 #error Unknown compiler for inline assembler
94 * This stub calls KiSystemService directly with a fake INT2E stack.
95 * Because EIP is pushed during the call, the handler will return here.
98 #define KernelModeStub_x86 " movl $0x%x, %%eax\n" \
99 " leal 4(%%esp), %%edx\n" \
101 " pushl $KGDT_R0_CODE\n" \
102 " call _KiSystemService\n" \
105 #define KernelModeStub_amd64 " movl $0x%x, %%eax\n" \
106 " call KiSystemService\n" \
109 /* For now, use the usermode stub. We'll optimize later */
110 #define KernelModeStub_ppc UserModeStub_ppc
112 #define KernelModeStub_mips " j KiSystemService\n" \
115 #define KernelModeStub_arm " mov ip, lr\n" \
119 #elif defined(_MSC_VER)
120 #define KernelModeStub_x86 " asm { \n" \
122 " lea edx, [esp+4]\n" \
124 " push KGDT_R0_CODE\n" \
125 " call _KiSystemService\n" \
129 #error Unknown compiler for inline assembler
132 /***** Arch Dependent Stuff ******/
133 struct ncitool_data_t
{
138 const char *global_header
;
139 const char *declaration
;
142 struct ncitool_data_t ncitool_data
[] = {
143 { "i386", 4, KernelModeStub_x86
, UserModeStub_x86
,
144 ".global _%s@%d\n", "_%s@%d:\n" },
145 { "amd64", 4, KernelModeStub_amd64
, UserModeStub_amd64
,
146 ".global %s\n", "%s:\n" },
147 { "powerpc", 4, KernelModeStub_ppc
, UserModeStub_ppc
,
148 "\t.globl %s\n", "%s:\n" },
149 { "mips", 4, KernelModeStub_mips
, UserModeStub_mips
,
150 "\t.globl %s\n", "%s:\n" },
151 { "arm", 4, KernelModeStub_arm
, UserModeStub_arm
,
152 "\t.globl %s\n", "%s:\n" },
156 #define ARGS_TO_BYTES(x) (x)*(ncitool_data[arch_sel].args_to_bytes)
157 #define UserModeStub ncitool_data[arch_sel].um_stub
158 #define KernelModeStub ncitool_data[arch_sel].km_stub
159 #define GlobalHeader ncitool_data[arch_sel].global_header
160 #define Declaration ncitool_data[arch_sel].declaration
162 /* FUNCTIONS ****************************************************************/
167 * Prints out the File Header for a Stub File.
170 * StubFile - Stub File to which to write the header.
172 * FileDescription - Description of the Stub file to which to write the header.
174 * FileLocation - Name of the Stub file to which to write the header.
180 * FileLocation is only used for printing the header.
184 WriteFileHeader(FILE * StubFile
,
185 char* FileDescription
,
188 /* This prints out the file header */
191 " * COPYRIGHT: See COPYING in the top level directory\n"
193 " * PROGRAMMER: Computer Generated File. See tools/nci/ncitool.c\n"
194 " * REMARK: DO NOT EDIT OR COMMIT MODIFICATIONS TO THIS FILE\n"
196 "#include <ndk/asm.h>\n\n",
204 * Prints out the File Header for a Stub File.
207 * StubFile - Stub File to which to write the header.
209 * FileDescription - Description of the Stub file to which to write the header.
211 * FileLocation - Name of the Stub file to which to write the header.
217 * FileLocation is only used for printing the header.
221 WriteStubHeader(FILE* StubFile
,
225 /* Export the function */
226 fprintf(StubFile
, GlobalHeader
, SyscallName
, StackBytes
);
229 fprintf(StubFile
, Declaration
, SyscallName
, StackBytes
);
234 * WriteKernelModeStub
236 * Prints out the Kernel Mode Stub for a System Call.
239 * StubFile - Stub File to which to write the header.
241 * SyscallName - Name of System Call for which to add the stub.
243 * StackBytes - Number of bytes on the stack to return after doing the system call.
245 * SyscallId - Service Descriptor Table ID for this System Call.
251 * On i386, StackBytes is the number of arguments x 4.
255 WriteKernelModeStub(FILE* StubFile
,
258 unsigned int SyscallId
)
260 /* Write the Stub Header and export the Function */
261 WriteStubHeader(StubFile
, SyscallName
, StackBytes
);
263 /* Write the Stub Code */
264 fprintf(StubFile
, KernelModeStub
, SyscallId
, StackBytes
);
270 * Prints out the User Mode Stub for a System Call.
273 * StubFile - Stub File to which to write the header.
275 * SyscallName - Name of System Call for which to add the stub.
277 * StackBytes - Number of bytes on the stack to return after doing the system call.
279 * SyscallId - Service Descriptor Table ID for this System Call.
285 * On i386, StackBytes is the number of arguments x 4.
289 WriteUserModeStub(FILE* StubFile
,
292 unsigned int SyscallId
)
294 /* Write the Stub Header and export the Function */
295 WriteStubHeader(StubFile
, SyscallName
, StackBytes
);
297 /* Write the Stub Code */
298 fprintf(StubFile
, UserModeStub
, SyscallId
, StackBytes
);
302 * GetNameAndArgumentsFromDb
304 * Parses an entry from a System Call Database, extracting
305 * the function's name and arguments that it takes.
308 * Line - Entry from the Database to parse.
310 * NtSyscallName - Output string to which to save the Function Name
312 * SyscallArguments - Output string to which to save the number of
313 * arguments that the function takes.
319 * On i386, StackBytes is the number of arguments x 4.
323 GetNameAndArgumentsFromDb(char Line
[],
324 char ** NtSyscallName
,
325 char ** SyscallArguments
)
330 /* Remove new line */
331 if ((s
= (char *) strchr(Line
,'\r')) != NULL
) {
335 /* Skip comments (#) and empty lines */
337 if ((*s
) != '#' && (*s
) != '\0') {
339 /* Extract the NtXXX name */
340 *NtSyscallName
= (char *)strtok(s
," \t");
342 /* Extract the argument count */
343 *SyscallArguments
= (char *)strtok(NULL
," \t");
345 /* Remove, if present, the trailing LF */
346 if ((stmp
= strchr(*SyscallArguments
, '\n')) != NULL
) {
352 /* Skip this entry */
353 *NtSyscallName
= NULL
;
354 *SyscallArguments
= NULL
;
361 * Parses a System Call Database and creates stubs for all the entries.
364 * SyscallDb - System Call Database to parse.
366 * UserModeFiles - Array of Usermode Stub Files to which to write the stubs.
368 * KernelModeFile - Kernelmode Stub Files to which to write the stubs.
370 * Index - Number of first syscall
372 * UserFiles - Number of Usermode Stub Files to create
374 * NeedsZw - Write Zw prefix?
384 CreateStubs(FILE * SyscallDb
,
385 FILE * UserModeFiles
[],
386 FILE * KernelModeFile
,
391 char Line
[INPUT_BUFFER_SIZE
];
393 char *SyscallArguments
;
397 /* We loop, incrementing the System Call Index, until the end of the file */
398 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
400 /* Extract the Name and Arguments */
401 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
402 if (SyscallArguments
!= NULL
)
403 StackBytes
= ARGS_TO_BYTES(strtoul(SyscallArguments
, NULL
, 0));
407 /* Make sure we really extracted something */
410 /* Create Usermode Stubs for Nt/Zw syscalls in each Usermode file */
412 for (i
= 0; i
< UserFiles
; i
++) {
414 /* Write the Nt Version */
415 WriteUserModeStub(UserModeFiles
[i
],
420 /* If a Zw Version is needed (was specified), write it too */
423 NtSyscallName
[0] = 'Z';
424 NtSyscallName
[1] = 'w';
425 WriteUserModeStub(UserModeFiles
[i
],
433 /* Create the Kernel coutnerparts (only Zw*, Nt* are the real functions!) */
434 if (KernelModeFile
) {
436 NtSyscallName
[0] = 'Z';
437 NtSyscallName
[1] = 'w';
438 WriteKernelModeStub(KernelModeFile
,
444 /* Only increase if we actually added something */
451 * CreateSystemServiceTable
453 * Parses a System Call Database and creates a System Call Service Table for it.
456 * SyscallDb - System Call Database to parse.
458 * SyscallTable - File in where to create System Call Service Table.
460 * Name - Name of the Service Table.
462 * FileLocation - Filename containing the Table.
468 * FileLocation is only used for the header generation.
472 CreateSystemServiceTable(FILE *SyscallDb
,
477 char Line
[INPUT_BUFFER_SIZE
];
479 char *SyscallArguments
;
482 /* Print the Header */
483 WriteFileHeader(SyscallTable
, "System Call Table for Native API", FileLocation
);
485 /* First we build the SSDT */
486 fprintf(SyscallTable
,"\n\n\n");
487 fprintf(SyscallTable
,"ULONG_PTR %sSSDT[] = {\n", Name
);
489 /* We loop, incrementing the System Call Index, until the end of the file */
490 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
492 /* Extract the Name and Arguments */
493 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
495 /* Make sure we really extracted something */
499 if (SyscallId
> 0) fprintf(SyscallTable
,",\n");
501 /* Write the syscall name in the service table. */
502 fprintf(SyscallTable
,"\t\t(ULONG_PTR)%s", NtSyscallName
);
504 /* Only increase if we actually added something */
509 /* Close the service table (C syntax) */
510 fprintf(SyscallTable
,"\n};\n");
512 /* Now we build the SSPT */
514 fprintf(SyscallTable
,"\n\n\n");
515 fprintf(SyscallTable
,"UCHAR %sSSPT[] = {\n", Name
);
517 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
519 /* Extract the Name and Arguments */
520 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
522 /* Make sure we really extracted something */
526 if (SyscallId
> 0) fprintf(SyscallTable
,",\n");
528 /* Write the syscall arguments in the argument table. */
529 if (SyscallArguments
!= NULL
)
530 fprintf(SyscallTable
,"\t\t%lu * sizeof(void *)",strtoul(SyscallArguments
, NULL
, 0));
532 fprintf(SyscallTable
,"\t\t0");
534 /* Only increase if we actually added something */
539 /* Close the service table (C syntax) */
540 fprintf(SyscallTable
,"\n};\n");
543 * We write some useful defines
545 fprintf(SyscallTable
, "\n\n#define MIN_SYSCALL_NUMBER 0\n");
546 fprintf(SyscallTable
, "#define MAX_SYSCALL_NUMBER %d\n", SyscallId
- 1);
547 fprintf(SyscallTable
, "#define NUMBER_OF_SYSCALLS %d\n", SyscallId
);
548 fprintf(SyscallTable
, "ULONG %sNumberOfSysCalls = %d;\n", Name
, SyscallId
);
554 * Prints out the Spec Entry for a System Call.
557 * SpecFile - Spec File to which to write the header.
559 * SyscallName - Name of System Call for which to add the stub.
561 * CountArguments - Number of arguments to the System Call.
571 WriteSpec(FILE* StubFile
,
573 unsigned CountArguments
)
577 fprintf(StubFile
, "@ stdcall %s", SyscallName
);
579 fputc ('(', StubFile
);
581 for (i
= 0; i
< CountArguments
; ++ i
)
582 fputs ("ptr ", StubFile
);
584 fputc (')', StubFile
);
585 fputc ('\n', StubFile
);
591 * Parses a System Call Database and creates a spec file for all the entries.
594 * SyscallDb - System Call Database to parse.
596 * Files - Array of Spec Files to which to write.
598 * CountFiles - Number of Spec Files to create
600 * UseZw - Use Zw prefix?
610 CreateSpec(FILE * SyscallDb
,
615 char Line
[INPUT_BUFFER_SIZE
];
617 char *SyscallArguments
;
618 unsigned CountArguments
;
620 /* We loop until the end of the file */
621 while ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
)) {
623 /* Extract the Name and Arguments */
624 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
625 CountArguments
= strtoul(SyscallArguments
, NULL
, 0);
627 /* Make sure we really extracted something */
631 for (i
= 0; i
< CountFiles
; i
++) {
639 if (UseZw
&& NtSyscallName
[0] == 'N' && NtSyscallName
[1] == 't') {
641 NtSyscallName
[0] = 'Z';
642 NtSyscallName
[1] = 'w';
653 void usage(char * argv0
)
655 printf("Usage: %s [-arch <arch>] sysfuncs.lst w32ksvc.db napi.h ssdt.h napi.S zw.S win32k.S win32k.S\n"
656 " sysfuncs.lst native system functions database\n"
657 " w32ksvc.db native graphic functions database\n"
658 " napi.h NTOSKRNL service table\n"
659 " ssdt.h WIN32K service table\n"
660 " napi.S NTDLL stubs\n"
661 " zw.S NTOSKRNL Zw stubs\n"
662 " win32k.S GDI32 stubs\n"
663 " win32k.S USER32 stubs\n"
664 " nt.pspec NTDLL exports\n"
665 " -arch is optional, default is %s\n",
671 int main(int argc
, char* argv
[])
673 FILE * Files
[Arguments
] = { };
674 int FileNumber
, ArgOffset
= 1;
675 char * OpenType
= "r";
677 /* Catch architecture argument */
678 if (argc
> 3 && !strcmp(argv
[1],"-arch")) {
679 for( arch_sel
= 0; ncitool_data
[arch_sel
].arch
; arch_sel
++ )
680 if (strcmp(argv
[2],ncitool_data
[arch_sel
].arch
) == 0)
682 if (!ncitool_data
[arch_sel
].arch
) {
683 printf("Invalid arch '%s'\n", argv
[2]);
689 /* Make sure all arguments all there */
690 if (argc
!= Arguments
+ ArgOffset
) {
695 /* Open all Output and bail out if any fail */
696 for (FileNumber
= 0; FileNumber
< Arguments
; FileNumber
++) {
699 if (FileNumber
== 2) OpenType
= "wb";
700 Files
[FileNumber
] = fopen(argv
[FileNumber
+ ArgOffset
], OpenType
);
702 /* Check for failure and error out if so */
703 if (!Files
[FileNumber
]) {
704 perror(argv
[FileNumber
+ ArgOffset
]);
709 /* Write the File Headers */
710 WriteFileHeader(Files
[NtosUserStubs
],
711 "System Call Stubs for Native API",
712 argv
[NtosUserStubs
+ ArgOffset
]);
714 WriteFileHeader(Files
[NtosKernelStubs
],
715 "System Call Stubs for Native API",
716 argv
[NtosKernelStubs
+ ArgOffset
]);
717 fputs("#include <ndk/asm.h>\n\n", Files
[NtosKernelStubs
]);
719 WriteFileHeader(Files
[Win32kStubs
],
720 "System Call Stubs for Native API",
721 argv
[Win32kStubs
+ ArgOffset
]);
723 /* Create the System Stubs */
724 CreateStubs(Files
[NativeSystemDb
],
725 &Files
[NtosUserStubs
],
726 Files
[NtosKernelStubs
],
731 /* Create the Graphics Stubs */
732 CreateStubs(Files
[NativeGuiDb
],
739 /* Create the Service Tables */
740 rewind(Files
[NativeSystemDb
]);
741 CreateSystemServiceTable(Files
[NativeSystemDb
],
742 Files
[NtosServiceTable
],
744 argv
[NtosServiceTable
+ ArgOffset
]);
746 rewind(Files
[NativeGuiDb
]);
747 CreateSystemServiceTable(Files
[NativeGuiDb
],
748 Files
[Win32kServiceTable
],
750 argv
[Win32kServiceTable
+ ArgOffset
]);
752 /* Create the Spec Files */
753 rewind(Files
[NativeSystemDb
]);
754 CreateSpec(Files
[NativeSystemDb
],
759 rewind(Files
[NativeSystemDb
]);
760 CreateSpec(Files
[NativeSystemDb
],
765 /* Close all files */
766 for (FileNumber
= 0; FileNumber
< Arguments
-ArgOffset
; FileNumber
++) {
769 fclose(Files
[FileNumber
]);