2 * Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
16 #include "gensyscalls_common.h"
18 #include "arch_gensyscalls.h"
19 // for the alignment type macros (only for the type names)
22 // macro trickery to create a string literal
23 #define MAKE_STRING(x) #x
24 #define EVAL_MACRO(macro, x) macro(x)
28 "Usage: gensyscallinfos <header> <syscall infos> <syscall types sizes>\n"
30 "Given the (preprocessed) header file that defines the syscall prototypes "
32 "command generates a source file consisting of syscall infos, which is "
34 "to build gensyscalls, which in turn generates the assembly syscall\n"
35 "definitions and code for the kernelland syscall dispatcher.\n"
37 " <header> - Input: The preprocessed header file with the\n"
38 " syscall prototypes.\n"
39 " <syscall infos> - Output: The syscall infos source file needed "
41 " build gensyscalls.\n"
42 " <syscall types sizes> - Output: A source file that will by another "
44 " step turned into a header file included by\n"
45 " <syscall infos>.\n";
49 print_usage(bool error
)
51 fprintf((error
? stderr
: stdout
), kUsage
);
56 Type(const char* type
) : type(type
) {}
57 Type(const string
& type
) : type(type
) {}
63 struct NamedType
: Type
{
64 NamedType(const char* type
, const char* name
)
65 : Type(type
), name(name
) {}
66 NamedType(const string
& type
, const string
& name
)
67 : Type(type
), name(name
) {}
75 Function() : fReturnType("") {}
77 void SetName(const string
& name
)
82 const string
& GetName() const
87 void AddParameter(const NamedType
& type
)
89 fParameters
.push_back(type
);
92 int CountParameters() const
94 return fParameters
.size();
97 const NamedType
& ParameterAt(int index
) const
99 return fParameters
[index
];
102 void SetReturnType(const Type
& type
)
107 const Type
& GetReturnType() const
114 vector
<NamedType
> fParameters
;
119 class Syscall
: public Function
{
121 string
GetKernelName() const
124 if (fName
.find("_kern_") == 0)
125 baseIndex
= strlen("_kern_");
126 else if (fName
.find("sys_") == 0)
127 baseIndex
= strlen("sys_");
128 string
kernelName("_user_");
129 kernelName
.append(string(fName
, baseIndex
));
137 Tokenizer(istream
& input
)
143 string
GetCurrentToken()
146 throw Exception("GetCurrentToken(): No current token!");
147 return fTokens
.front();
150 string
GetNextToken()
152 return GetNextToken(NULL
);
155 string
GetNextToken(stack
<string
>& skippedTokens
)
157 return GetNextToken(&skippedTokens
);
160 string
GetNextToken(stack
<string
>* skippedTokens
)
166 while (fTokens
.empty())
170 skippedTokens
->push(fTokens
.front());
171 return fTokens
.front();
174 void ExpectToken(const string
& expectedToken
)
176 string token
= GetCurrentToken();
177 if (expectedToken
!= token
) {
178 throw ParseException(string("Unexpected token `") + token
179 + "'. Expected was `" + expectedToken
+ "'.");
183 void ExpectNextToken(const string
& expectedToken
)
186 ExpectToken(expectedToken
);
189 bool CheckToken(const string
& expectedToken
)
191 string token
= GetCurrentToken();
192 return (expectedToken
== token
);
195 bool CheckNextToken(const string
& expectedToken
)
198 bool result
= CheckToken(expectedToken
);
204 void PutCurrentToken()
207 throw Exception("GetCurrentToken(): No current token!");
211 void PutToken(string token
)
217 fTokens
.push_front(token
);
220 void PutTokens(stack
<string
>& tokens
)
226 while (!tokens
.empty()) {
227 fTokens
.push_front(tokens
.top());
237 if (!fInput
.getline(buffer
, sizeof(buffer
)))
238 throw EOFException("Unexpected end of input.");
241 int len
= strlen(buffer
);
243 for (int i
= 0; i
< len
; i
++) {
247 line
.push_back(string(buffer
+ tokenStart
, buffer
+ i
));
261 if (tokenStart
< i
) {
262 line
.push_back(string(buffer
+ tokenStart
,
265 line
.push_back(string(buffer
+ i
, buffer
+ i
+ 1));
270 if (tokenStart
< len
)
271 line
.push_back(string(buffer
+ tokenStart
, buffer
+ len
));
272 // drop the line, if it starts with "# <number>", as those are
273 // directions from the pre-processor to the compiler
274 if (line
.size() >= 2) {
275 if (line
[0] == "#" && isdigit(line
[1][0]))
278 for (int i
= 0; i
< (int)line
.size(); i
++)
279 fTokens
.push_back(line
[i
]);
284 list
<string
> fTokens
;
292 int Run(int argc
, char** argv
)
296 && (string(argv
[1]) == "-h" || string(argv
[1]) == "--help")) {
304 _ParseSyscalls(argv
[1]);
305 _WriteSyscallInfoFile(argv
[2]);
306 _WriteSyscallTypeSizes(argv
[3]);
311 void _ParseSyscalls(const char* filename
)
313 // open the input file
314 ifstream
file(filename
, ifstream::in
);
316 throw new IOException(string("Failed to open `") + filename
+ "'.");
317 // parse the syscalls
318 Tokenizer
tokenizer(file
);
319 // find "#pragma syscalls begin"
321 while (tokenizer
.GetNextToken() != "#");
322 stack
<string
> skippedTokens
;
323 if (tokenizer
.GetNextToken(skippedTokens
) == "pragma"
324 && tokenizer
.GetNextToken(skippedTokens
) == "syscalls"
325 && tokenizer
.GetNextToken(skippedTokens
) == "begin") {
328 tokenizer
.PutTokens(skippedTokens
);
330 // parse the functions
331 while (!tokenizer
.CheckNextToken("#")) {
333 _ParseSyscall(tokenizer
, syscall
);
334 fSyscalls
.push_back(syscall
);
336 // expect "pragma syscalls end"
337 tokenizer
.ExpectNextToken("pragma");
338 tokenizer
.ExpectNextToken("syscalls");
339 tokenizer
.ExpectNextToken("end");
342 void _WriteSyscallInfoFile(const char* filename
)
344 // open the syscall info file
345 ofstream
file(filename
, ofstream::out
| ofstream::trunc
);
347 throw new IOException(string("Failed to open `") + filename
+ "'.");
350 file
<< "#include \"gensyscalls.h\"" << endl
;
351 file
<< "#include \"syscall_types_sizes.h\"" << endl
;
354 file
<< "const char* const kReturnTypeAlignmentType = \""
355 EVAL_MACRO(MAKE_STRING
, SYSCALL_RETURN_TYPE_ALIGNMENT_TYPE
)
357 file
<< "const char* const kParameterAlignmentType = \""
358 EVAL_MACRO(MAKE_STRING
, SYSCALL_PARAMETER_ALIGNMENT_TYPE
)
360 file
<< "const int kReturnTypeAlignmentSize = "
361 "SYSCALL_RETURN_TYPE_ALIGNMENT_SIZE;" << endl
;
362 file
<< "const int kParameterAlignmentSize = "
363 "SYSCALL_PARAMETER_ALIGNMENT_SIZE;" << endl
;
366 file
<< "SyscallVector* create_syscall_vector() {" << endl
;
367 file
<< "\tSyscallVector* syscallVector = SyscallVector::Create();"
369 file
<< "\tSyscall* syscall;" << endl
;
372 for (int i
= 0; i
< (int)fSyscalls
.size(); i
++) {
373 const Syscall
& syscall
= fSyscalls
[i
];
375 // syscall = syscallVector->CreateSyscall("syscallName",
376 // "syscallKernelName");
377 file
<< "\tsyscall = syscallVector->CreateSyscall(\""
378 << syscall
.GetName() << "\", \""
379 << syscall
.GetKernelName() << "\");" << endl
;
381 const Type
& returnType
= syscall
.GetReturnType();
383 // syscall->SetReturnType<(SYSCALL_RETURN_TYPE_SIZE_<i>,
385 file
<< "\tsyscall->SetReturnType("
386 << "SYSCALL_RETURN_TYPE_SIZE_" << i
<< ", \""
387 << returnType
.type
<< "\");" << endl
;
390 int paramCount
= syscall
.CountParameters();
391 for (int k
= 0; k
< paramCount
; k
++) {
392 const NamedType
& param
= syscall
.ParameterAt(k
);
393 // syscall->AddParameter(SYSCALL_PARAMETER_SIZE_<i>_<k>,
394 // "parameterTypeName", "parameterName");
395 file
<< "\tsyscall->AddParameter("
396 << "SYSCALL_PARAMETER_SIZE_" << i
<< "_" << k
397 << ", \"" << param
.type
<< "\", \"" << param
.name
<< "\");"
404 file
<< "\treturn syscallVector;" << endl
;
408 void _WriteSyscallTypeSizes(const char* filename
)
410 // open the syscall info file
411 ofstream
file(filename
, ofstream::out
| ofstream::trunc
);
413 throw new IOException(string("Failed to open `") + filename
+ "'.");
416 file
<< "#include <computed_asm_macros.h>" << endl
;
417 file
<< "#include <syscalls.h>" << endl
;
419 file
<< "#include \"arch_gensyscalls.h\"" << endl
;
421 file
<< "void dummy() {" << endl
;
423 file
<< "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_RETURN_TYPE_ALIGNMENT_SIZE, "
424 "sizeof(SYSCALL_RETURN_TYPE_ALIGNMENT_TYPE));" << endl
;
425 file
<< "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_PARAMETER_ALIGNMENT_SIZE, "
426 "sizeof(SYSCALL_PARAMETER_ALIGNMENT_TYPE));" << endl
;
430 for (int i
= 0; i
< (int)fSyscalls
.size(); i
++) {
431 const Syscall
& syscall
= fSyscalls
[i
];
432 const Type
& returnType
= syscall
.GetReturnType();
434 if (returnType
.type
== "void") {
435 file
<< "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_RETURN_TYPE_SIZE_"
436 << i
<< ", 0);" << endl
;
438 file
<< "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_RETURN_TYPE_SIZE_"
439 << i
<< ", sizeof(" << returnType
.type
<< "));" << endl
;
443 int paramCount
= syscall
.CountParameters();
444 for (int k
= 0; k
< paramCount
; k
++) {
445 const NamedType
& param
= syscall
.ParameterAt(k
);
446 file
<< "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_PARAMETER_SIZE_" << i
447 << "_" << k
<< ", sizeof(" << param
.type
<< "));" << endl
;
456 void _ParseSyscall(Tokenizer
& tokenizer
, Syscall
& syscall
)
458 // get return type and function name
459 vector
<string
> returnType
;
460 while (tokenizer
.GetNextToken() != "(") {
461 string token
= tokenizer
.GetCurrentToken();
462 // strip leading "extern"
463 if (!returnType
.empty() || token
!= "extern")
464 returnType
.push_back(token
);
466 if (returnType
.size() < 2) {
467 throw ParseException("Error while parsing function "
470 syscall
.SetName(returnType
[returnType
.size() - 1]);
471 returnType
.pop_back();
472 string
returnTypeString(returnType
[0]);
473 for (int i
= 1; i
< (int)returnType
.size(); i
++) {
474 returnTypeString
+= " ";
475 returnTypeString
+= returnType
[i
];
477 syscall
.SetReturnType(returnTypeString
);
479 if (!tokenizer
.CheckNextToken(")")) {
480 _ParseParameter(tokenizer
, syscall
);
481 while (!tokenizer
.CheckNextToken(")")) {
482 tokenizer
.ExpectNextToken(",");
483 _ParseParameter(tokenizer
, syscall
);
486 tokenizer
.ExpectNextToken(";");
489 void _ParseParameter(Tokenizer
& tokenizer
, Syscall
& syscall
)
492 while (tokenizer
.GetNextToken() != ")"
493 && tokenizer
.GetCurrentToken() != ",") {
494 string token
= tokenizer
.GetCurrentToken();
495 type
.push_back(token
);
497 // This must be a function pointer. We deal with that in a
499 _ParseFunctionPointerParameter(tokenizer
, syscall
, type
);
503 tokenizer
.PutCurrentToken();
504 if (type
.size() < 2) {
505 if (type
.size() == 1 && type
[0] == "void") {
509 throw ParseException("Error while parsing function parameter.");
512 // last component is the parameter name
513 string typeName
= type
.back();
516 string
typeString(type
[0]);
517 for (int i
= 1; i
< (int)type
.size(); i
++) {
519 typeString
+= type
[i
];
521 syscall
.AddParameter(NamedType(typeString
, typeName
));
524 void _ParseFunctionPointerParameter(Tokenizer
& tokenizer
, Syscall
& syscall
,
525 vector
<string
>& type
)
527 // When this method is entered, the return type and the opening
528 // parenthesis must already be parse and stored in the supplied type
530 if (type
.size() < 2) {
531 throw ParseException("Error parsing function parameter. "
534 // read all the "*"s there are
535 while (tokenizer
.CheckNextToken("*"))
537 // now comes the parameter name, if specified -- skip it
539 if (!tokenizer
.CheckNextToken(")")) {
540 typeName
= tokenizer
.GetNextToken();
541 tokenizer
.ExpectNextToken(")");
543 throw ParseException("Error while parsing function parameter. "
544 "No parameter name.");
547 // the function parameters
548 tokenizer
.ExpectNextToken("(");
550 while (!tokenizer
.CheckNextToken(")"))
551 type
.push_back(tokenizer
.GetNextToken());
553 // compose the type string and add it to the syscall parameters
554 string
typeString(type
[0]);
555 for (int i
= 1; i
< (int)type
.size(); i
++) {
557 typeString
+= type
[i
];
559 syscall
.AddParameter(NamedType(typeString
, typeName
));
563 vector
<Syscall
> fSyscalls
;
568 main(int argc
, char** argv
)
571 return Main().Run(argc
, argv
);
572 } catch (Exception
& exception
) {
573 fprintf(stderr
, "%s\n", exception
.what());