HaikuDepot: notify work status from main window
[haiku.git] / src / tools / gensyscalls / gensyscalls.cpp
blob340c0a5a1eec7d963733eabde468e4799851a3ae
1 /*
2 * Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "gensyscalls.h"
9 #include <cstdio>
10 #include <cstdlib>
11 #include <fstream>
12 #include <string>
13 #include <string.h>
14 #include <vector>
16 #include "gensyscalls_common.h"
18 using std::vector;
21 // print_usage
22 static void
23 print_usage(bool error)
25 fprintf(error ? stderr : stdout,
26 "Usage: gensyscalls [ -c <calls> ] [ -d <dispatcher> ] [ -n <numbers> "
27 "]\n"
28 " [ -t <table> ] [ -s <strace> ]\n"
29 "\n"
30 "The command is able to generate several syscalls related source "
31 "files.\n"
32 "\n"
33 " <calls> - Output: The assembly source file "
34 "implementing the\n"
35 " actual syscalls.\n"
36 " <dispatcher> - Output: The C source file to be included by "
37 "the\n"
38 " syscall dispatcher source file.\n"
39 " <numbers> - Output: The C/assembly include files "
40 "defining the\n"
41 " syscall numbers.\n"
42 " <table> - Output: A C source file containing an array "
43 "with\n"
44 " infos about the syscalls\n"
45 " <strace> - Output: A C source file for strace "
46 "support.\n");
50 // #pragma mark - Type
53 Type::Type(const char* name, int size, int usedSize,
54 const char* alignmentTypeName)
56 fName(name),
57 fSize(size),
58 fUsedSize(usedSize),
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),
72 fOffset(offset)
77 // #pragma mark - Syscall
80 struct Syscall::ParameterVector : public vector<Parameter*> {
84 Syscall::Syscall(const char* name, const char* kernelName)
86 fName(name),
87 fKernelName(kernelName),
88 fReturnType(NULL),
89 fParameters(new ParameterVector)
94 Syscall::~Syscall()
96 delete fReturnType;
98 int count = CountParameters();
99 for (int i = 0; i < count; i++)
100 delete ParameterAt(i);
101 delete fParameters;
106 Syscall::CountParameters() const
108 return fParameters->size();
112 Parameter*
113 Syscall::ParameterAt(int index) const
115 if (index < 0 || index >= CountParameters())
116 return NULL;
118 return (*fParameters)[index];
122 Parameter*
123 Syscall::LastParameter() const
125 return ParameterAt(CountParameters() - 1);
129 void
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);
142 Type*
143 Syscall::SetReturnType(const char* name, int size, int usedSize,
144 const char* alignmentTypeName)
146 delete fReturnType;
147 return fReturnType = new Type(name, size, usedSize, alignmentTypeName);
151 Parameter*
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);
158 return parameter;
161 void
162 Syscall::AddParameter(int size, const char* typeName, const char* parameterName)
164 // compute offset
165 int offset = 0;
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,
176 alignmentType);
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++)
199 delete SyscallAt(i);
200 delete fSyscalls;
204 SyscallVector*
205 SyscallVector::Create()
207 return new SyscallVector;
212 SyscallVector::CountSyscalls() const
214 return fSyscalls->size();
218 Syscall*
219 SyscallVector::SyscallAt(int index) const
221 if (index < 0 || index >= CountSyscalls())
222 return NULL;
224 return (*fSyscalls)[index];
228 Syscall*
229 SyscallVector::CreateSyscall(const char* name, const char* kernelName)
231 Syscall* syscall = new Syscall(name, kernelName);
232 fSyscalls->push_back(syscall);
233 return syscall;
237 // #pragma mark -
240 class Main {
241 public:
242 int Run(int argc, char** argv)
244 // parse arguments
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") {
254 print_usage(false);
255 return 0;
256 } else if (arg == "-c") {
257 if (argi + 1 >= argc) {
258 print_usage(true);
259 return 1;
261 syscallsFile = argv[++argi];
262 } else if (arg == "-d") {
263 if (argi + 1 >= argc) {
264 print_usage(true);
265 return 1;
267 dispatcherFile = argv[++argi];
268 } else if (arg == "-n") {
269 if (argi + 1 >= argc) {
270 print_usage(true);
271 return 1;
273 numbersFile = argv[++argi];
274 } else if (arg == "-t") {
275 if (argi + 1 >= argc) {
276 print_usage(true);
277 return 1;
279 tableFile = argv[++argi];
280 } else if (arg == "-s") {
281 if (argi + 1 >= argc) {
282 print_usage(true);
283 return 1;
285 straceFile = argv[++argi];
286 } else {
287 print_usage(true);
288 return 1;
291 fSyscallVector = create_syscall_vector();
292 fSyscallCount = fSyscallVector->CountSyscalls();
293 if (!syscallsFile && !dispatcherFile && !numbersFile && !tableFile
294 && !straceFile) {
295 printf("Found %d syscalls.\n", fSyscallCount);
296 return 0;
298 // generate the output
299 if (syscallsFile)
300 _WriteSyscallsFile(syscallsFile);
301 if (dispatcherFile)
302 _WriteDispatcherFile(dispatcherFile);
303 if (numbersFile)
304 _WriteNumbersFile(numbersFile);
305 if (tableFile)
306 _WriteTableFile(tableFile);
307 if (straceFile)
308 _WriteSTraceFile(straceFile);
309 return 0;
312 void _WriteSyscallsFile(const char* filename)
314 // open the syscalls output file
315 ofstream file(filename, ofstream::out | ofstream::trunc);
316 if (!file.is_open())
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();
323 int paramSize = 0;
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);
340 if (!file.is_open())
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;
347 file << "\t";
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()
357 << "*)args";
358 } else {
359 file << "*(" << _GetPointerType(parameter->TypeName())
360 << ")args";
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()
368 << ")";
369 } else {
370 file << ", *(" << _GetPointerType(parameter->TypeName())
371 << ")((char*)args + " << parameter->Offset()
372 << ")";
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);
385 if (!file.is_open())
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?)
401 string defineName;
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);
412 if (!file.is_open())
413 throw IOException(string("Failed to open `") + filename + "'.");
415 // output syscall count macro
416 file << "#define SYSCALL_COUNT " << fSyscallCount << endl;
417 file << endl;
419 // assembler guard
420 file << "#ifndef _ASSEMBLER" << endl;
421 file << endl;
423 // includes
424 file << "#include <TypeConstants.h>" << endl;
425 file << endl;
427 // output syscall count
428 file << "const int kSyscallCount = SYSCALL_COUNT;" << endl;
429 file << endl;
431 // syscall infos array preamble
432 file << "const syscall_info kSyscallInfos[] = {" << endl;
434 // the syscall infos
435 for (int i = 0; i < fSyscallCount; i++) {
436 const Syscall* syscall = fSyscallVector->SyscallAt(i);
438 // get the parameter size
439 int paramSize = 0;
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;
450 file << endl;
452 // syscall parameters infos array preamble
453 file << "const extended_syscall_info kExtendedSyscallInfos[] = {"
454 << endl;
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 << ","
463 << endl;
465 // return type
466 Type* returnType = syscall->ReturnType();
467 file << "\t\t{ " << returnType->Size() << ", "
468 << returnType->UsedSize() << ", "
469 << _GetTypeCode(returnType) << " }," << endl;
471 // parameters
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);
497 if (!file.is_open())
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
503 << "{" << 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) {
516 // chunk end
517 file << endl;
518 if (i > 0)
519 file << "#endif" << endl;
520 // chunk begin
521 file << "#ifdef SYSCALLS_CHUNK_" << (i / chunkSize) << endl;
524 // spacing, comment
525 file << endl;
526 file << "\t// " << syscall->Name() << endl;
528 // create the return type handler
529 const char* returnType = syscall->ReturnType()->TypeName();
530 file << "\thandler = TypeHandlerFactory<"
531 << returnType
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;
548 // add the parameter
549 file << "\tsyscall->AddParameter(\""
550 << parameter->ParameterName() << "\", "
551 << parameter->Offset() << ", \"" << parameter->TypeName()
552 << "\", handler);" << endl;
556 // last syscall chunk end
557 file << "#endif" << endl;
559 // function end
560 file << "}" << endl;
563 static string _GetPointerType(const char* type)
565 const char* parenthesis = strchr(type, ')');
566 if (!parenthesis)
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, '*')) {
576 // pointer type
577 // check, if it is a string constant ("const char *" or
578 // "char const *")
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";
592 } else {
593 // non-pointer type
594 switch (type->Size()) {
595 case 1:
596 return "B_INT8_TYPE";
597 case 2:
598 return "B_INT16_TYPE";
599 case 4:
600 return "B_INT32_TYPE";
601 case 8:
602 return "B_INT64_TYPE";
603 default:
604 return "B_RAW_TYPE";
609 static string _GetTypeCodeTokenize(const char*& type)
611 // skip whitespace
612 while (*type != '\0' && isspace(*type))
613 type++;
615 switch (*type) {
616 case '\0':
617 return "";
619 case '*':
620 case '(':
621 case ')':
622 case '&':
623 return string(type++, 1);
625 default:
627 if (*type != '_' && !isalpha(*type)) {
628 // probably invalid, just return something
629 return string(type++, 1);
632 // an identifier
633 const char* start = type;
634 while (*type == '_' || isalnum(*type))
635 type++;
636 return string(start, type - start);
641 private:
642 SyscallVector* fSyscallVector;
643 int fSyscallCount;
648 main(int argc, char** argv)
650 try {
651 return Main().Run(argc, argv);
652 } catch (Exception &exception) {
653 fprintf(stderr, "%s\n", exception.what());
654 return 1;