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_ppc " stwu 1,-16(1)\n" \
69 #define UserModeStub_mips " li $8, KUSER_SHARED_SYSCALL\n" \
74 #define UserModeStub_arm " swi #0x%x\n" \
77 #elif defined(_MSC_VER)
78 #define UserModeStub_x86 " asm { \n" \
80 " mov ecx, KUSER_SHARED_SYSCALL\n" \
85 #error Unknown compiler for inline assembler
89 * This stub calls KiSystemService directly with a fake INT2E stack.
90 * Because EIP is pushed during the call, the handler will return here.
93 #define KernelModeStub_x86 " movl $0x%x, %%eax\n" \
94 " leal 4(%%esp), %%edx\n" \
96 " pushl $KGDT_R0_CODE\n" \
97 " call _KiSystemService\n" \
100 /* For now, use the usermode stub. We'll optimize later */
101 #define KernelModeStub_ppc UserModeStub_ppc
103 #define KernelModeStub_mips " j KiSystemService\n" \
106 #define KernelModeStub_arm " mov ip, lr\n" \
110 #elif defined(_MSC_VER)
111 #define KernelModeStub_x86 " asm { \n" \
113 " lea edx, [esp+4]\n" \
115 " push KGDT_R0_CODE\n" \
116 " call _KiSystemService\n" \
120 #error Unknown compiler for inline assembler
123 /***** Arch Dependent Stuff ******/
124 struct ncitool_data_t
{
129 const char *global_header
;
130 const char *declaration
;
133 struct ncitool_data_t ncitool_data
[] = {
134 { "i386", 4, KernelModeStub_x86
, UserModeStub_x86
,
135 ".global _%s@%d\n", "_%s@%d:\n" },
136 { "powerpc", 4, KernelModeStub_ppc
, UserModeStub_ppc
,
137 "\t.globl %s\n", "%s:\n" },
138 { "mips", 4, KernelModeStub_mips
, UserModeStub_mips
,
139 "\t.globl %s\n", "%s:\n" },
140 { "arm", 4, KernelModeStub_arm
, UserModeStub_arm
,
141 "\t.globl %s\n", "%s:\n" },
145 #define ARGS_TO_BYTES(x) (x)*(ncitool_data[arch_sel].args_to_bytes)
146 #define UserModeStub ncitool_data[arch_sel].um_stub
147 #define KernelModeStub ncitool_data[arch_sel].km_stub
148 #define GlobalHeader ncitool_data[arch_sel].global_header
149 #define Declaration ncitool_data[arch_sel].declaration
151 /* FUNCTIONS ****************************************************************/
156 * Prints out the File Header for a Stub File.
159 * StubFile - Stub File to which to write the header.
161 * FileDescription - Description of the Stub file to which to write the header.
163 * FileLocation - Name of the Stub file to which to write the header.
169 * FileLocation is only used for printing the header.
173 WriteFileHeader(FILE * StubFile
,
174 char* FileDescription
,
177 /* This prints out the file header */
180 " * COPYRIGHT: See COPYING in the top level directory\n"
182 " * PROGRAMMER: Computer Generated File. See tools/nci/ncitool.c\n"
183 " * REMARK: DO NOT EDIT OR COMMIT MODIFICATIONS TO THIS FILE\n"
185 "#include <ndk/asm.h>\n\n",
193 * Prints out the File Header for a Stub File.
196 * StubFile - Stub File to which to write the header.
198 * FileDescription - Description of the Stub file to which to write the header.
200 * FileLocation - Name of the Stub file to which to write the header.
206 * FileLocation is only used for printing the header.
210 WriteStubHeader(FILE* StubFile
,
214 /* Export the function */
215 fprintf(StubFile
, GlobalHeader
, SyscallName
, StackBytes
);
218 fprintf(StubFile
, Declaration
, SyscallName
, StackBytes
);
223 * WriteKernelModeStub
225 * Prints out the Kernel Mode Stub for a System Call.
228 * StubFile - Stub File to which to write the header.
230 * SyscallName - Name of System Call for which to add the stub.
232 * StackBytes - Number of bytes on the stack to return after doing the system call.
234 * SyscallId - Service Descriptor Table ID for this System Call.
240 * On i386, StackBytes is the number of arguments x 4.
244 WriteKernelModeStub(FILE* StubFile
,
247 unsigned int SyscallId
)
249 /* Write the Stub Header and export the Function */
250 WriteStubHeader(StubFile
, SyscallName
, StackBytes
);
252 /* Write the Stub Code */
253 fprintf(StubFile
, KernelModeStub
, SyscallId
, StackBytes
);
259 * Prints out the User Mode Stub for a System Call.
262 * StubFile - Stub File to which to write the header.
264 * SyscallName - Name of System Call for which to add the stub.
266 * StackBytes - Number of bytes on the stack to return after doing the system call.
268 * SyscallId - Service Descriptor Table ID for this System Call.
274 * On i386, StackBytes is the number of arguments x 4.
278 WriteUserModeStub(FILE* StubFile
,
281 unsigned int SyscallId
)
283 /* Write the Stub Header and export the Function */
284 WriteStubHeader(StubFile
, SyscallName
, StackBytes
);
286 /* Write the Stub Code */
287 fprintf(StubFile
, UserModeStub
, SyscallId
, StackBytes
);
291 * GetNameAndArgumentsFromDb
293 * Parses an entry from a System Call Database, extracting
294 * the function's name and arguments that it takes.
297 * Line - Entry from the Database to parse.
299 * NtSyscallName - Output string to which to save the Function Name
301 * SyscallArguments - Output string to which to save the number of
302 * arguments that the function takes.
308 * On i386, StackBytes is the number of arguments x 4.
312 GetNameAndArgumentsFromDb(char Line
[],
313 char ** NtSyscallName
,
314 char ** SyscallArguments
)
319 /* Remove new line */
320 if ((s
= (char *) strchr(Line
,'\r')) != NULL
) {
324 /* Skip comments (#) and empty lines */
326 if ((*s
) != '#' && (*s
) != '\0') {
328 /* Extract the NtXXX name */
329 *NtSyscallName
= (char *)strtok(s
," \t");
331 /* Extract the argument count */
332 *SyscallArguments
= (char *)strtok(NULL
," \t");
334 /* Remove, if present, the trailing LF */
335 if ((stmp
= strchr(*SyscallArguments
, '\n')) != NULL
) {
341 /* Skip this entry */
342 *NtSyscallName
= NULL
;
343 *SyscallArguments
= NULL
;
350 * Parses a System Call Database and creates stubs for all the entries.
353 * SyscallDb - System Call Database to parse.
355 * UserModeFiles - Array of Usermode Stub Files to which to write the stubs.
357 * KernelModeFile - Kernelmode Stub Files to which to write the stubs.
359 * Index - Number of first syscall
361 * UserFiles - Number of Usermode Stub Files to create
363 * NeedsZw - Write Zw prefix?
373 CreateStubs(FILE * SyscallDb
,
374 FILE * UserModeFiles
[],
375 FILE * KernelModeFile
,
380 char Line
[INPUT_BUFFER_SIZE
];
382 char *SyscallArguments
;
386 /* We loop, incrementing the System Call Index, until the end of the file */
387 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
389 /* Extract the Name and Arguments */
390 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
391 if (SyscallArguments
!= NULL
)
392 StackBytes
= ARGS_TO_BYTES(strtoul(SyscallArguments
, NULL
, 0));
396 /* Make sure we really extracted something */
399 /* Create Usermode Stubs for Nt/Zw syscalls in each Usermode file */
401 for (i
= 0; i
< UserFiles
; i
++) {
403 /* Write the Nt Version */
404 WriteUserModeStub(UserModeFiles
[i
],
409 /* If a Zw Version is needed (was specified), write it too */
412 NtSyscallName
[0] = 'Z';
413 NtSyscallName
[1] = 'w';
414 WriteUserModeStub(UserModeFiles
[i
],
422 /* Create the Kernel coutnerparts (only Zw*, Nt* are the real functions!) */
423 if (KernelModeFile
) {
425 NtSyscallName
[0] = 'Z';
426 NtSyscallName
[1] = 'w';
427 WriteKernelModeStub(KernelModeFile
,
433 /* Only increase if we actually added something */
440 * CreateSystemServiceTable
442 * Parses a System Call Database and creates a System Call Service Table for it.
445 * SyscallDb - System Call Database to parse.
447 * SyscallTable - File in where to create System Call Service Table.
449 * Name - Name of the Service Table.
451 * FileLocation - Filename containing the Table.
457 * FileLocation is only used for the header generation.
461 CreateSystemServiceTable(FILE *SyscallDb
,
466 char Line
[INPUT_BUFFER_SIZE
];
468 char *SyscallArguments
;
471 /* Print the Header */
472 WriteFileHeader(SyscallTable
, "System Call Table for Native API", FileLocation
);
474 /* First we build the SSDT */
475 fprintf(SyscallTable
,"\n\n\n");
476 fprintf(SyscallTable
,"ULONG_PTR %sSSDT[] = {\n", Name
);
478 /* We loop, incrementing the System Call Index, until the end of the file */
479 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
481 /* Extract the Name and Arguments */
482 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
484 /* Make sure we really extracted something */
488 if (SyscallId
> 0) fprintf(SyscallTable
,",\n");
490 /* Write the syscall name in the service table. */
491 fprintf(SyscallTable
,"\t\t(ULONG_PTR)%s", NtSyscallName
);
493 /* Only increase if we actually added something */
498 /* Close the service table (C syntax) */
499 fprintf(SyscallTable
,"\n};\n");
501 /* Now we build the SSPT */
503 fprintf(SyscallTable
,"\n\n\n");
504 fprintf(SyscallTable
,"UCHAR %sSSPT[] = {\n", Name
);
506 for (SyscallId
= 0; ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
));) {
508 /* Extract the Name and Arguments */
509 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
511 /* Make sure we really extracted something */
515 if (SyscallId
> 0) fprintf(SyscallTable
,",\n");
517 /* Write the syscall arguments in the argument table. */
518 if (SyscallArguments
!= NULL
)
519 fprintf(SyscallTable
,"\t\t%lu * sizeof(void *)",strtoul(SyscallArguments
, NULL
, 0));
521 fprintf(SyscallTable
,"\t\t0");
523 /* Only increase if we actually added something */
528 /* Close the service table (C syntax) */
529 fprintf(SyscallTable
,"\n};\n");
532 * We write some useful defines
534 fprintf(SyscallTable
, "\n\n#define MIN_SYSCALL_NUMBER 0\n");
535 fprintf(SyscallTable
, "#define MAX_SYSCALL_NUMBER %d\n", SyscallId
- 1);
536 fprintf(SyscallTable
, "#define NUMBER_OF_SYSCALLS %d\n", SyscallId
);
537 fprintf(SyscallTable
, "ULONG %sNumberOfSysCalls = %d;\n", Name
, SyscallId
);
543 * Prints out the Spec Entry for a System Call.
546 * SpecFile - Spec File to which to write the header.
548 * SyscallName - Name of System Call for which to add the stub.
550 * CountArguments - Number of arguments to the System Call.
560 WriteSpec(FILE* StubFile
,
562 unsigned CountArguments
)
566 fprintf(StubFile
, "@ stdcall %s", SyscallName
);
568 fputc ('(', StubFile
);
570 for (i
= 0; i
< CountArguments
; ++ i
)
571 fputs ("ptr ", StubFile
);
573 fputc (')', StubFile
);
574 fputc ('\n', StubFile
);
580 * Parses a System Call Database and creates a spec file for all the entries.
583 * SyscallDb - System Call Database to parse.
585 * Files - Array of Spec Files to which to write.
587 * CountFiles - Number of Spec Files to create
589 * UseZw - Use Zw prefix?
599 CreateSpec(FILE * SyscallDb
,
604 char Line
[INPUT_BUFFER_SIZE
];
606 char *SyscallArguments
;
607 unsigned CountArguments
;
609 /* We loop until the end of the file */
610 while ((!feof(SyscallDb
)) && (fgets(Line
, sizeof(Line
), SyscallDb
) != NULL
)) {
612 /* Extract the Name and Arguments */
613 GetNameAndArgumentsFromDb(Line
, &NtSyscallName
, &SyscallArguments
);
614 CountArguments
= strtoul(SyscallArguments
, NULL
, 0);
616 /* Make sure we really extracted something */
620 for (i
= 0; i
< CountFiles
; i
++) {
628 if (UseZw
&& NtSyscallName
[0] == 'N' && NtSyscallName
[1] == 't') {
630 NtSyscallName
[0] = 'Z';
631 NtSyscallName
[1] = 'w';
642 void usage(char * argv0
)
644 printf("Usage: %s [-arch <arch>] sysfuncs.lst w32ksvc.db napi.h ssdt.h napi.S zw.S win32k.S win32k.S\n"
645 " sysfuncs.lst native system functions database\n"
646 " w32ksvc.db native graphic functions database\n"
647 " napi.h NTOSKRNL service table\n"
648 " ssdt.h WIN32K service table\n"
649 " napi.S NTDLL stubs\n"
650 " zw.S NTOSKRNL Zw stubs\n"
651 " win32k.S GDI32 stubs\n"
652 " win32k.S USER32 stubs\n"
653 " nt.pspec NTDLL exports\n"
654 " -arch is optional, default is %s\n",
660 int main(int argc
, char* argv
[])
662 FILE * Files
[Arguments
] = { };
663 int FileNumber
, ArgOffset
= 1;
664 char * OpenType
= "r";
666 /* Catch architecture argument */
667 if (argc
> 3 && !strcmp(argv
[1],"-arch")) {
668 for( arch_sel
= 0; ncitool_data
[arch_sel
].arch
; arch_sel
++ )
669 if (strcmp(argv
[2],ncitool_data
[arch_sel
].arch
) == 0)
671 if (!ncitool_data
[arch_sel
].arch
) {
672 printf("Invalid arch '%s'\n", argv
[2]);
678 /* Make sure all arguments all there */
679 if (argc
!= Arguments
+ ArgOffset
) {
684 /* Open all Output and bail out if any fail */
685 for (FileNumber
= 0; FileNumber
< Arguments
; FileNumber
++) {
688 if (FileNumber
== 2) OpenType
= "wb";
689 Files
[FileNumber
] = fopen(argv
[FileNumber
+ ArgOffset
], OpenType
);
691 /* Check for failure and error out if so */
692 if (!Files
[FileNumber
]) {
693 perror(argv
[FileNumber
+ ArgOffset
]);
698 /* Write the File Headers */
699 WriteFileHeader(Files
[NtosUserStubs
],
700 "System Call Stubs for Native API",
701 argv
[NtosUserStubs
+ ArgOffset
]);
703 WriteFileHeader(Files
[NtosKernelStubs
],
704 "System Call Stubs for Native API",
705 argv
[NtosKernelStubs
+ ArgOffset
]);
706 fputs("#include <ndk/asm.h>\n\n", Files
[NtosKernelStubs
]);
708 WriteFileHeader(Files
[Win32kStubs
],
709 "System Call Stubs for Native API",
710 argv
[Win32kStubs
+ ArgOffset
]);
712 /* Create the System Stubs */
713 CreateStubs(Files
[NativeSystemDb
],
714 &Files
[NtosUserStubs
],
715 Files
[NtosKernelStubs
],
720 /* Create the Graphics Stubs */
721 CreateStubs(Files
[NativeGuiDb
],
728 /* Create the Service Tables */
729 rewind(Files
[NativeSystemDb
]);
730 CreateSystemServiceTable(Files
[NativeSystemDb
],
731 Files
[NtosServiceTable
],
733 argv
[NtosServiceTable
+ ArgOffset
]);
735 rewind(Files
[NativeGuiDb
]);
736 CreateSystemServiceTable(Files
[NativeGuiDb
],
737 Files
[Win32kServiceTable
],
739 argv
[Win32kServiceTable
+ ArgOffset
]);
741 /* Create the Spec Files */
742 rewind(Files
[NativeSystemDb
]);
743 CreateSpec(Files
[NativeSystemDb
],
748 rewind(Files
[NativeSystemDb
]);
749 CreateSpec(Files
[NativeSystemDb
],
754 /* Close all files */
755 for (FileNumber
= 0; FileNumber
< Arguments
-ArgOffset
; FileNumber
++) {
758 fclose(Files
[FileNumber
]);