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