1b3f9618d9ed8f8e4524d12cbd8567c23d772269
[reactos.git] / reactos / tools / nci / ncitool.c
1 /*
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.
9 *
10 */
11
12 /* INCLUDE ******************************************************************/
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <malloc.h>
18
19 /* DEFINES ****************************************************************/
20
21 #define INPUT_BUFFER_SIZE 255
22 #define Arguments 8
23
24 /******* Table Indexes ************/
25 #define MAIN_INDEX 0x0
26 #define WIN32K_INDEX 0x1000
27
28 /******* Argument List ************/
29 /* First, define the Databases */
30 #define NativeSystemDb 0
31 #define NativeGuiDb 1
32
33 /* Now the Service Tables */
34 #define NtosServiceTable 2
35 #define Win32kServiceTable 3
36
37 /* And finally, the stub files. */
38 #define NtosUserStubs 4
39 #define NtosKernelStubs 5
40 #define Win32kGdiStubs 6
41 #define Win32kUserStubs 7
42
43 /********** Stub Code ************/
44
45 /*
46 * This stubs calls into KUSER_SHARED_DATA where either a
47 * sysenter or interrupt is performed, depending on CPU support.
48 */
49 #if defined(__GNUC__)
50 #define UserModeStub_x86 " movl $0x%x, %%eax\n" \
51 " movl $KUSER_SHARED_SYSCALL, %%ecx\n" \
52 " call *%%ecx\n" \
53 " ret $0x%x\n\n"
54 #elif defined(_MSC_VER)
55 #define UserModeStub_x86 " asm { \n" \
56 " mov eax, %xh\n" \
57 " mov ecx, KUSER_SHARED_SYSCALL\n" \
58 " call [ecx]\n" \
59 " ret %xh\n" \
60 " }\n"
61 #else
62 #error Unknown compiler for inline assembler
63 #endif
64
65 /*
66 * This stub calls KiSystemService directly with a fake INT2E stack.
67 * Because EIP is pushed during the call, the handler will return here.
68 */
69 #if defined(__GNUC__)
70 #define KernelModeStub_x86 " movl $0x%x, %%eax\n" \
71 " leal 4(%%esp), %%edx\n" \
72 " pushfl\n" \
73 " pushl $KERNEL_CS\n" \
74 " call _KiSystemService\n" \
75 " ret $0x%x\n\n"
76 #elif defined(_MSC_VER)
77 #define KernelModeStub_x86 " asm { \n" \
78 " mov eax, %xh\n" \
79 " lea edx, [esp+4]\n" \
80 " pushf\n" \
81 " push KERNEL_CS\n" \
82 " call _KiSystemService\n" \
83 " ret %xh\n" \
84 " }\n"
85 #else
86 #error Unknown compiler for inline assembler
87 #endif
88
89 /***** Arch Dependent Stuff ******/
90 //#ifdef _M_IX86
91 #define ARGS_TO_BYTES(x) x*4
92 #define UserModeStub UserModeStub_x86
93 #define KernelModeStub KernelModeStub_x86
94
95 //#elseif
96 //#error Unsupported Architecture
97 //#endif
98
99 /* FUNCTIONS ****************************************************************/
100
101 /*++
102 * WriteFileHeader
103 *
104 * Prints out the File Header for a Stub File.
105 *
106 * Params:
107 * StubFile - Stub File to which to write the header.
108 *
109 * FileDescription - Description of the Stub file to which to write the header.
110 *
111 * FileLocation - Name of the Stub file to which to write the header.
112 *
113 * Returns:
114 * None.
115 *
116 * Remarks:
117 * FileLocation is only used for printing the header.
118 *
119 *--*/
120 void
121 WriteFileHeader(FILE * StubFile,
122 char* FileDescription,
123 char* FileLocation)
124 {
125 /* This prints out the file header */
126 fprintf(StubFile,
127 "/* FILE: %s\n"
128 " * COPYRIGHT: See COPYING in the top level directory\n"
129 " * PURPOSE: %s\n"
130 " * PROGRAMMER: Computer Generated File. See tools/nci/ncitool.c\n"
131 " * REMARK: DO NOT EDIT OR COMMIT MODIFICATIONS TO THIS FILE\n"
132 " */\n\n\n"
133 "#define KUSER_SHARED_SYSCALL 0x7FFE0300\n\n",
134 FileDescription,
135 FileLocation);
136 }
137
138 /*++
139 * WriteFileHeader
140 *
141 * Prints out the File Header for a Stub File.
142 *
143 * Params:
144 * StubFile - Stub File to which to write the header.
145 *
146 * FileDescription - Description of the Stub file to which to write the header.
147 *
148 * FileLocation - Name of the Stub file to which to write the header.
149 *
150 * Returns:
151 * None.
152 *
153 * Remarks:
154 * FileLocation is only used for printing the header.
155 *
156 *--*/
157 void
158 WriteStubHeader(FILE* StubFile,
159 char* SyscallName,
160 unsigned StackBytes)
161 {
162 /* Export the function */
163 fprintf(StubFile, ".global _%s@%d\n", SyscallName, StackBytes);
164
165 /* Define it */
166 fprintf(StubFile, "_%s@%d:\n\n", SyscallName, StackBytes);
167 }
168
169
170 /*++
171 * WriteKernelModeStub
172 *
173 * Prints out the Kernel Mode Stub for a System Call.
174 *
175 * Params:
176 * StubFile - Stub File to which to write the header.
177 *
178 * SyscallName - Name of System Call for which to add the stub.
179 *
180 * StackBytes - Number of bytes on the stack to return after doing the system call.
181 *
182 * SyscallId - Service Descriptor Table ID for this System Call.
183 *
184 * Returns:
185 * None.
186 *
187 * Remarks:
188 * On i386, StackBytes is the number of arguments x 4.
189 *
190 *--*/
191 void
192 WriteKernelModeStub(FILE* StubFile,
193 char* SyscallName,
194 unsigned StackBytes,
195 unsigned int SyscallId)
196 {
197 /* Write the Stub Header and export the Function */
198 WriteStubHeader(StubFile, SyscallName, StackBytes);
199
200 /* Write the Stub Code */
201 fprintf(StubFile, KernelModeStub, SyscallId, StackBytes);
202 }
203
204 /*++
205 * WriteUserModeStub
206 *
207 * Prints out the User Mode Stub for a System Call.
208 *
209 * Params:
210 * StubFile - Stub File to which to write the header.
211 *
212 * SyscallName - Name of System Call for which to add the stub.
213 *
214 * StackBytes - Number of bytes on the stack to return after doing the system call.
215 *
216 * SyscallId - Service Descriptor Table ID for this System Call.
217 *
218 * Returns:
219 * None.
220 *
221 * Remarks:
222 * On i386, StackBytes is the number of arguments x 4.
223 *
224 *--*/
225 void
226 WriteUserModeStub(FILE* StubFile,
227 char* SyscallName,
228 unsigned StackBytes,
229 unsigned int SyscallId)
230 {
231 /* Write the Stub Header and export the Function */
232 WriteStubHeader(StubFile, SyscallName, StackBytes);
233
234 /* Write the Stub Code */
235 fprintf(StubFile, UserModeStub, SyscallId, StackBytes);
236 }
237
238 /*++
239 * GetNameAndArgumentsFromDb
240 *
241 * Parses an entry from a System Call Database, extracting
242 * the function's name and arguments that it takes.
243 *
244 * Params:
245 * Line - Entry from the Database to parse.
246 *
247 * NtSyscallName - Output string to which to save the Function Name
248 *
249 * SyscallArguments - Output string to which to save the number of
250 * arguments that the function takes.
251 *
252 * Returns:
253 * None.
254 *
255 * Remarks:
256 * On i386, StackBytes is the number of arguments x 4.
257 *
258 *--*/
259 void
260 GetNameAndArgumentsFromDb(char Line[],
261 char ** NtSyscallName,
262 char ** SyscallArguments)
263 {
264 char *s;
265 char *stmp;
266
267 /* Remove new line */
268 if ((s = (char *) strchr(Line,'\r')) != NULL) {
269 *s = '\0';
270 }
271
272 /* Skip comments (#) and empty lines */
273 s = &Line[0];
274 if ((*s) != '#' && (*s) != '\0') {
275
276 /* Extract the NtXXX name */
277 *NtSyscallName = (char *)strtok(s," \t");
278
279 /* Extract the argument count */
280 *SyscallArguments = (char *)strtok(NULL," \t");
281
282 /* Remove, if present, the trailing LF */
283 if ((stmp = strchr(*SyscallArguments, '\n')) != NULL) {
284 *stmp = '\0';
285 }
286
287 } else {
288
289 /* Skip this entry */
290 *NtSyscallName = NULL;
291 }
292 }
293
294 /*++
295 * CreateStubs
296 *
297 * Parses a System Call Database and creates stubs for all the entries.
298 *
299 * Params:
300 * SyscallDb - System Call Database to parse.
301 *
302 * UserModeFiles - Array of Usermode Stub Files to which to write the stubs.
303 *
304 * KernelModeFile - Kernelmode Stub Files to which to write the stubs.
305 *
306 * Index - Name of System Call for which to add the stub.
307 *
308 * UserFiles - Number of bytes on the stack to return after doing the system call.
309 *
310 * NeedsZw - Service Descriptor Table ID for this System Call.
311 *
312 * Returns:
313 * None.
314 *
315 * Remarks:
316 * None.
317 *
318 *--*/
319 void
320 CreateStubs(FILE * SyscallDb,
321 FILE * UserModeFiles[],
322 FILE * KernelModeFile,
323 unsigned Index,
324 unsigned UserFiles,
325 unsigned NeedsZw)
326 {
327 char Line[INPUT_BUFFER_SIZE];
328 char *NtSyscallName;
329 char *ZwSyscallName = NULL;
330 char *SyscallArguments;
331 int SyscallId;
332 unsigned StackBytes;
333
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));) {
336
337 /* Extract the Name and Arguments */
338 GetNameAndArgumentsFromDb(Line, &NtSyscallName, &SyscallArguments);
339 StackBytes = ARGS_TO_BYTES(strtoul(SyscallArguments, NULL, 0));
340
341 /* Make sure we really extracted something */
342 if (NtSyscallName) {
343
344 /* Create the ZwXXX name, if requested */
345 if (NeedsZw) {
346 ZwSyscallName = alloca(strlen(NtSyscallName));
347 strcpy(ZwSyscallName, NtSyscallName);
348 ZwSyscallName[0] = 'Z';
349 ZwSyscallName[1] = 'w';
350 }
351
352 /* Create Usermode Stubs for Nt/Zw syscalls in each Usermode file */
353 int i;
354 for (i= 0; i < UserFiles; i++) {
355
356 /* Write the Nt Version */
357 WriteUserModeStub(UserModeFiles[i],
358 NtSyscallName,
359 StackBytes,
360 SyscallId | Index);
361
362 /* If a Zw Version is needed (was specified), write it too */
363 if (ZwSyscallName) WriteUserModeStub(UserModeFiles[i],
364 ZwSyscallName,
365 StackBytes,
366 SyscallId | Index);
367
368 }
369
370 /* Create the Kernel coutnerparts (only Zw*, Nt* are the real functions!) */
371 if (KernelModeFile) WriteKernelModeStub(KernelModeFile,
372 ZwSyscallName,
373 StackBytes,
374 SyscallId | Index);
375
376 /* Only increase if we actually added something */
377 SyscallId++;
378 }
379 }
380 }
381
382 /*++
383 * CreateSystemServiceTable
384 *
385 * Parses a System Call Database and creates a System Call Service Table for it.
386 *
387 * Params:
388 * SyscallDb - System Call Database to parse.
389 *
390 * SyscallTable - File in where to create System Call Service Table.
391 *
392 * Name - Name of the Service Table.
393 *
394 * FileLocation - Filename containing the Table.
395 *
396 * Returns:
397 * None.
398 *
399 * Remarks:
400 * FileLocation is only used for the header generation.
401 *
402 *--*/
403 void
404 CreateSystemServiceTable(FILE *SyscallDb,
405 FILE *SyscallTable,
406 char * Name,
407 char * FileLocation)
408 {
409 char Line[INPUT_BUFFER_SIZE];
410 char *NtSyscallName;
411 char *SyscallArguments;
412 int SyscallId;
413
414 /* Print the Header */
415 WriteFileHeader(SyscallTable, "System Call Table for Native API", FileLocation);
416
417 /* First we build the SSDT */
418 fprintf(SyscallTable,"\n\n\n");
419 fprintf(SyscallTable,"SSDT %sSSDT[] = {\n", Name);
420
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));) {
423
424 /* Extract the Name and Arguments */
425 GetNameAndArgumentsFromDb(Line, &NtSyscallName, &SyscallArguments);
426
427 /* Make sure we really extracted something */
428 if (NtSyscallName) {
429
430 /* Add a new line */
431 if (SyscallId > 0) fprintf(SyscallTable,",\n");
432
433 /* Write the syscall name in the service table. */
434 fprintf(SyscallTable,"\t\t(PVOID (NTAPI *)(VOID))%s", NtSyscallName);
435
436 /* Only increase if we actually added something */
437 SyscallId++;
438 }
439 }
440
441 /* Close the service table (C syntax) */
442 fprintf(SyscallTable,"\n};\n");
443
444 /* Now we build the SSPT */
445 rewind(SyscallDb);
446 fprintf(SyscallTable,"\n\n\n");
447 fprintf(SyscallTable,"SSPT %sSSPT[] = {\n", Name);
448
449 for (SyscallId = 0; ((!feof(SyscallDb)) && (fgets(Line, sizeof(Line), SyscallDb) != NULL));) {
450
451 /* Extract the Name and Arguments */
452 GetNameAndArgumentsFromDb(Line, &NtSyscallName, &SyscallArguments);
453
454 /* Make sure we really extracted something */
455 if (NtSyscallName) {
456
457 /* Add a new line */
458 if (SyscallId > 0) fprintf(SyscallTable,",\n");
459
460 /* Write the syscall arguments in the argument table. */
461 fprintf(SyscallTable,"\t\t%lu * sizeof(void *)",strtoul(SyscallArguments, NULL, 0));
462
463 /* Only increase if we actually added something */
464 SyscallId++;
465 }
466 }
467
468 /* Close the service table (C syntax) */
469 fprintf(SyscallTable,"\n};\n");
470
471 /*
472 * We write some useful defines
473 */
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);
478 }
479
480 void usage(char * argv0)
481 {
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",
491 argv0
492 );
493 }
494
495 int main(int argc, char* argv[])
496 {
497 FILE * Files[Arguments];
498 int FileNumber;
499 char * OpenType = "r";
500
501 /* Make sure all arguments all there */
502 if (argc != Arguments + 1) {
503 usage(argv[0]);
504 return(1);
505 }
506
507 /* Open all Output and bail out if any fail */
508 for (FileNumber = 0; FileNumber < Arguments; FileNumber++) {
509
510 /* Open the File */
511 if (FileNumber == 2) OpenType = "wb";
512 Files[FileNumber] = fopen(argv[FileNumber + 1], OpenType);
513
514 /* Check for failure and error out if so */
515 if (!Files[FileNumber]) {
516 perror(argv[FileNumber + 1]);
517 return (1);
518 }
519
520 }
521
522 /* Write the File Headers */
523 WriteFileHeader(Files[NtosUserStubs],
524 "System Call Stubs for Native API",
525 argv[NtosUserStubs + 1]);
526
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]);
531
532 WriteFileHeader(Files[Win32kGdiStubs],
533 "System Call Stubs for Native API",
534 argv[Win32kGdiStubs + 1]);
535
536 WriteFileHeader(Files[Win32kUserStubs],
537 "System Call Stubs for Native API",
538 argv[Win32kUserStubs + 1]);
539
540
541 /* Create the System Stubs */
542 CreateStubs(Files[NativeSystemDb],
543 &Files[NtosUserStubs],
544 Files[NtosKernelStubs],
545 MAIN_INDEX,
546 1,
547 1);
548
549 /* Create the Graphics Stubs */
550 CreateStubs(Files[NativeGuiDb],
551 &Files[Win32kGdiStubs],
552 NULL,
553 WIN32K_INDEX,
554 2,
555 0);
556
557 /* Rewind the databases */
558 rewind(Files[NativeSystemDb]);
559 rewind(Files[NativeGuiDb]);
560
561 /* Create the Service Tables */
562 CreateSystemServiceTable(Files[NativeSystemDb],
563 Files[NtosServiceTable],
564 "Main",
565 argv[NtosServiceTable + 1]);
566
567 CreateSystemServiceTable(Files[NativeGuiDb],
568 Files[Win32kServiceTable],
569 "Win32k",
570 argv[Win32kServiceTable + 1]);
571
572 /* Close all files */
573 for (FileNumber = 0; FileNumber < Arguments; FileNumber++) {
574
575 /* Close the File */
576 fclose(Files[FileNumber]);
577
578 }
579
580 return(0);
581 }