2 * Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include "gensyscalls.h"
16 #include "gensyscalls_common.h"
23 print_usage(bool error
)
25 fprintf(error
? stderr
: stdout
,
26 "Usage: gensyscalls [ -c <calls> ] [ -d <dispatcher> ] [ -n <numbers> "
28 " [ -t <table> ] [ -s <strace> ]\n"
30 "The command is able to generate several syscalls related source "
33 " <calls> - Output: The assembly source file "
36 " <dispatcher> - Output: The C source file to be included by "
38 " syscall dispatcher source file.\n"
39 " <numbers> - Output: The C/assembly include files "
42 " <table> - Output: A C source file containing an array "
44 " infos about the syscalls\n"
45 " <strace> - Output: A C source file for strace "
50 // #pragma mark - Type
53 Type::Type(const char* name
, int size
, int usedSize
,
54 const char* alignmentTypeName
)
59 fAlignmentType(alignmentTypeName
)
64 // #pragma mark - Parameter
67 Parameter::Parameter(const char* typeName
, const char* parameterName
,
68 int size
, int usedSize
, int offset
, const char* alignmentTypeName
)
70 Type(typeName
, size
, usedSize
, alignmentTypeName
),
71 fParameterName(parameterName
),
77 // #pragma mark - Syscall
80 struct Syscall::ParameterVector
: public vector
<Parameter
*> {
84 Syscall::Syscall(const char* name
, const char* kernelName
)
87 fKernelName(kernelName
),
89 fParameters(new ParameterVector
)
98 int count
= CountParameters();
99 for (int i
= 0; i
< count
; i
++)
100 delete ParameterAt(i
);
106 Syscall::CountParameters() const
108 return fParameters
->size();
113 Syscall::ParameterAt(int index
) const
115 if (index
< 0 || index
>= CountParameters())
118 return (*fParameters
)[index
];
123 Syscall::LastParameter() const
125 return ParameterAt(CountParameters() - 1);
130 Syscall::SetReturnType(int size
, const char* name
)
132 int usedSize
= (size
+ kReturnTypeAlignmentSize
- 1)
133 / kReturnTypeAlignmentSize
* kReturnTypeAlignmentSize
;
134 const char* alignmentType
135 = size
!= usedSize
&& size
< kReturnTypeAlignmentSize
136 ? kReturnTypeAlignmentType
: 0;
138 SetReturnType(name
, size
, usedSize
, alignmentType
);
143 Syscall::SetReturnType(const char* name
, int size
, int usedSize
,
144 const char* alignmentTypeName
)
147 return fReturnType
= new Type(name
, size
, usedSize
, alignmentTypeName
);
152 Syscall::AddParameter(const char* typeName
, const char* parameterName
,
153 int size
, int usedSize
, int offset
, const char* alignmentTypeName
)
155 Parameter
* parameter
= new Parameter(typeName
, parameterName
, size
,
156 usedSize
, offset
, alignmentTypeName
);
157 fParameters
->push_back(parameter
);
162 Syscall::AddParameter(int size
, const char* typeName
, const char* parameterName
)
166 if (Parameter
* previous
= LastParameter())
167 offset
= previous
->Offset() + previous
->UsedSize();
169 int usedSize
= (size
+ kParameterAlignmentSize
- 1)
170 / kParameterAlignmentSize
* kParameterAlignmentSize
;
171 const char* alignmentType
172 = size
!= usedSize
&& size
< kParameterAlignmentSize
173 ? kParameterAlignmentType
: 0;
175 AddParameter(typeName
, parameterName
, size
, usedSize
, offset
,
180 // #pragma mark - SyscallVector
183 struct SyscallVector::_SyscallVector
: public vector
<Syscall
*> {
188 SyscallVector::SyscallVector()
190 fSyscalls(new _SyscallVector
)
195 SyscallVector::~SyscallVector()
197 int count
= CountSyscalls();
198 for (int i
= 0; i
< count
; i
++)
205 SyscallVector::Create()
207 return new SyscallVector
;
212 SyscallVector::CountSyscalls() const
214 return fSyscalls
->size();
219 SyscallVector::SyscallAt(int index
) const
221 if (index
< 0 || index
>= CountSyscalls())
224 return (*fSyscalls
)[index
];
229 SyscallVector::CreateSyscall(const char* name
, const char* kernelName
)
231 Syscall
* syscall
= new Syscall(name
, kernelName
);
232 fSyscalls
->push_back(syscall
);
242 int Run(int argc
, char** argv
)
245 const char* syscallsFile
= NULL
;
246 const char* dispatcherFile
= NULL
;
247 const char* numbersFile
= NULL
;
248 const char* tableFile
= NULL
;
249 const char* straceFile
= NULL
;
251 for (int argi
= 1; argi
< argc
; argi
++) {
252 string
arg(argv
[argi
]);
253 if (arg
== "-h" || arg
== "--help") {
256 } else if (arg
== "-c") {
257 if (argi
+ 1 >= argc
) {
261 syscallsFile
= argv
[++argi
];
262 } else if (arg
== "-d") {
263 if (argi
+ 1 >= argc
) {
267 dispatcherFile
= argv
[++argi
];
268 } else if (arg
== "-n") {
269 if (argi
+ 1 >= argc
) {
273 numbersFile
= argv
[++argi
];
274 } else if (arg
== "-t") {
275 if (argi
+ 1 >= argc
) {
279 tableFile
= argv
[++argi
];
280 } else if (arg
== "-s") {
281 if (argi
+ 1 >= argc
) {
285 straceFile
= argv
[++argi
];
291 fSyscallVector
= create_syscall_vector();
292 fSyscallCount
= fSyscallVector
->CountSyscalls();
293 if (!syscallsFile
&& !dispatcherFile
&& !numbersFile
&& !tableFile
295 printf("Found %d syscalls.\n", fSyscallCount
);
298 // generate the output
300 _WriteSyscallsFile(syscallsFile
);
302 _WriteDispatcherFile(dispatcherFile
);
304 _WriteNumbersFile(numbersFile
);
306 _WriteTableFile(tableFile
);
308 _WriteSTraceFile(straceFile
);
312 void _WriteSyscallsFile(const char* filename
)
314 // open the syscalls output file
315 ofstream
file(filename
, ofstream::out
| ofstream::trunc
);
317 throw IOException(string("Failed to open `") + filename
+ "'.");
319 // output the syscalls definitions
320 for (int i
= 0; i
< fSyscallCount
; i
++) {
321 const Syscall
* syscall
= fSyscallVector
->SyscallAt(i
);
322 int paramCount
= syscall
->CountParameters();
324 // XXX: Currently the SYSCALL macros support 4 byte aligned
325 // parameters only. This has to change, of course.
326 for (int k
= 0; k
< paramCount
; k
++) {
327 const Parameter
* parameter
= syscall
->ParameterAt(k
);
328 int size
= parameter
->UsedSize();
329 paramSize
+= (size
+ 3) / 4 * 4;
331 file
<< "SYSCALL" << (paramSize
/ 4) << "("
332 << syscall
->Name() << ", " << i
<< ")" << endl
;
336 void _WriteDispatcherFile(const char* filename
)
338 // open the dispatcher output file
339 ofstream
file(filename
, ofstream::out
| ofstream::trunc
);
341 throw IOException(string("Failed to open `") + filename
+ "'.");
343 // output the case statements
344 for (int i
= 0; i
< fSyscallCount
; i
++) {
345 const Syscall
* syscall
= fSyscallVector
->SyscallAt(i
);
346 file
<< "case " << i
<< ":" << endl
;
348 if (string(syscall
->ReturnType()->TypeName()) != "void")
349 file
<< "*_returnValue = ";
350 file
<< syscall
->KernelName() << "(";
351 int paramCount
= syscall
->CountParameters();
352 if (paramCount
> 0) {
353 Parameter
* parameter
= syscall
->ParameterAt(0);
354 if (parameter
->AlignmentTypeName()) {
355 file
<< "(" << parameter
->TypeName() << ")*("
356 << parameter
->AlignmentTypeName()
359 file
<< "*(" << _GetPointerType(parameter
->TypeName())
362 for (int k
= 1; k
< paramCount
; k
++) {
363 parameter
= syscall
->ParameterAt(k
);
364 if (parameter
->AlignmentTypeName()) {
365 file
<< ", (" << parameter
->TypeName() << ")*("
366 << parameter
->AlignmentTypeName()
367 << "*)((char*)args + " << parameter
->Offset()
370 file
<< ", *(" << _GetPointerType(parameter
->TypeName())
371 << ")((char*)args + " << parameter
->Offset()
376 file
<< ");" << endl
;
377 file
<< "\tbreak;" << endl
;
381 void _WriteNumbersFile(const char* filename
)
383 // open the syscall numbers output file
384 ofstream
file(filename
, ofstream::out
| ofstream::trunc
);
386 throw IOException(string("Failed to open `") + filename
+ "'.");
388 // output the defines
389 const char* prefix
= "_user_";
390 size_t prefixLen
= strlen(prefix
);
391 for (int i
= 0; i
< fSyscallCount
; i
++) {
392 const Syscall
* syscall
= fSyscallVector
->SyscallAt(i
);
393 string
name(syscall
->KernelName());
395 // drop the leading "_user_" prefix
396 if (name
.find(prefix
) != 0)
397 throw Exception(string("Bad kernel name: `") + name
+ "'.");
398 name
= string(name
, prefixLen
);
400 // convert to upper case (is there no function for that?)
402 for (int k
= 0; k
< (int)name
.length(); k
++)
403 defineName
+= toupper(name
[k
]);
404 file
<< "#define SYSCALL_" << defineName
<< " " << i
<< endl
;
408 void _WriteTableFile(const char* filename
)
410 // open the syscall table output file
411 ofstream
file(filename
, ofstream::out
| ofstream::trunc
);
413 throw IOException(string("Failed to open `") + filename
+ "'.");
415 // output syscall count macro
416 file
<< "#define SYSCALL_COUNT " << fSyscallCount
<< endl
;
420 file
<< "#ifndef _ASSEMBLER" << endl
;
424 file
<< "#include <TypeConstants.h>" << endl
;
427 // output syscall count
428 file
<< "const int kSyscallCount = SYSCALL_COUNT;" << endl
;
431 // syscall infos array preamble
432 file
<< "const syscall_info kSyscallInfos[] = {" << endl
;
435 for (int i
= 0; i
< fSyscallCount
; i
++) {
436 const Syscall
* syscall
= fSyscallVector
->SyscallAt(i
);
438 // get the parameter size
440 if (Parameter
* parameter
= syscall
->LastParameter())
441 paramSize
= parameter
->Offset() + parameter
->UsedSize();
443 // output the info for the syscall
444 file
<< "\t{ (void *)" << syscall
->KernelName() << ", "
445 << paramSize
<< " }," << endl
;
448 // syscall infos array end
449 file
<< "};" << endl
;
452 // syscall parameters infos array preamble
453 file
<< "const extended_syscall_info kExtendedSyscallInfos[] = {"
456 // the syscall parameters infos
457 for (int i
= 0; i
< fSyscallCount
; i
++) {
458 const Syscall
* syscall
= fSyscallVector
->SyscallAt(i
);
459 int paramCount
= syscall
->CountParameters();
461 file
<< "\t{" << endl
;
462 file
<< "\t\t\"" << syscall
->Name() << "\", " << paramCount
<< ","
466 Type
* returnType
= syscall
->ReturnType();
467 file
<< "\t\t{ " << returnType
->Size() << ", "
468 << returnType
->UsedSize() << ", "
469 << _GetTypeCode(returnType
) << " }," << endl
;
472 file
<< "\t\t{" << endl
;
474 for (int k
= 0; k
< paramCount
; k
++) {
475 const Parameter
* parameter
= syscall
->ParameterAt(k
);
476 file
<< "\t\t\t{ " << parameter
->Offset() << ", "
477 << parameter
->Size() << ", "
478 << parameter
->UsedSize() << ", "
479 << _GetTypeCode(parameter
) << " }," << endl
;
482 file
<< "\t\t}" << endl
;
483 file
<< "\t}," << endl
;
486 // syscall parameters infos array end
487 file
<< "};" << endl
;
489 // assembler guard end
490 file
<< "#endif // _ASSEMBLER" << endl
;
493 void _WriteSTraceFile(const char* filename
)
495 // open the syscall table output file
496 ofstream
file(filename
, ofstream::out
| ofstream::trunc
);
498 throw IOException(string("Failed to open `") + filename
+ "'.");
500 // the file defines a single function get_syscalls
501 file
<< "void" << endl
502 << "GET_SYSCALLS(vector<Syscall*> &syscalls)" << endl
504 << "\tSyscall *syscall;" << endl
505 << "\tTypeHandler *handler;" << endl
506 << "(void)syscall;" << endl
507 << "(void)handler;" << endl
;
509 int chunkSize
= (fSyscallCount
+ 19) / 20;
511 // iterate through the syscalls
512 for (int i
= 0; i
< fSyscallCount
; i
++) {
513 const Syscall
* syscall
= fSyscallVector
->SyscallAt(i
);
515 if (i
% chunkSize
== 0) {
519 file
<< "#endif" << endl
;
521 file
<< "#ifdef SYSCALLS_CHUNK_" << (i
/ chunkSize
) << endl
;
526 file
<< "\t// " << syscall
->Name() << endl
;
528 // create the return type handler
529 const char* returnType
= syscall
->ReturnType()->TypeName();
530 file
<< "\thandler = TypeHandlerFactory<"
532 << ">::Create();" << endl
;
534 // create the syscall
535 file
<< "\tsyscall = new Syscall(\"" << syscall
->Name() << "\", "
536 << "\"" << returnType
<< "\", "<< "handler);" << endl
;
537 file
<< "\tsyscalls.push_back(syscall);" << endl
;
539 // add the parameters
540 int paramCount
= syscall
->CountParameters();
541 for (int k
= 0; k
< paramCount
; k
++) {
542 const Parameter
* parameter
= syscall
->ParameterAt(k
);
544 // create the parameter type handler
545 file
<< "\thandler = TypeHandlerFactory<"
546 << parameter
->TypeName() << ">::Create();" << endl
;
549 file
<< "\tsyscall->AddParameter(\""
550 << parameter
->ParameterName() << "\", "
551 << parameter
->Offset() << ", \"" << parameter
->TypeName()
552 << "\", handler);" << endl
;
556 // last syscall chunk end
557 file
<< "#endif" << endl
;
563 static string
_GetPointerType(const char* type
)
565 const char* parenthesis
= strchr(type
, ')');
567 return string(type
) + "*";
568 // function pointer type
569 return string(type
, parenthesis
- type
) + "*" + parenthesis
;
572 static string
_GetTypeCode(const Type
* type
)
574 const char* typeName
= type
->TypeName();
575 if (strchr(typeName
, '*')) {
577 // check, if it is a string constant ("const char *" or
579 if ((_GetTypeCodeTokenize(typeName
) == "const"
580 && _GetTypeCodeTokenize(typeName
) == "char"
581 && _GetTypeCodeTokenize(typeName
) == "*"
582 && _GetTypeCodeTokenize(typeName
) == "")
583 || (_GetTypeCodeTokenize(typeName
) == "char"
584 && _GetTypeCodeTokenize(typeName
) == "const"
585 && _GetTypeCodeTokenize(typeName
) == "*"
586 && _GetTypeCodeTokenize(typeName
) == "")) {
587 return "B_STRING_TYPE";
590 // not a string constant
591 return "B_POINTER_TYPE";
594 switch (type
->Size()) {
596 return "B_INT8_TYPE";
598 return "B_INT16_TYPE";
600 return "B_INT32_TYPE";
602 return "B_INT64_TYPE";
609 static string
_GetTypeCodeTokenize(const char*& type
)
612 while (*type
!= '\0' && isspace(*type
))
623 return string(type
++, 1);
627 if (*type
!= '_' && !isalpha(*type
)) {
628 // probably invalid, just return something
629 return string(type
++, 1);
633 const char* start
= type
;
634 while (*type
== '_' || isalnum(*type
))
636 return string(start
, type
- start
);
642 SyscallVector
* fSyscallVector
;
648 main(int argc
, char** argv
)
651 return Main().Run(argc
, argv
);
652 } catch (Exception
&exception
) {
653 fprintf(stderr
, "%s\n", exception
.what());