HaikuDepot: notify work status from main window
[haiku.git] / src / tools / gensyscalls / gensyscallinfos.cpp
blobcf828314599a7cb309e9693933ef8fc394cf4a16
1 /*
2 * Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <cstdio>
8 #include <cstdlib>
9 #include <fstream>
10 #include <list>
11 #include <stack>
12 #include <string>
13 #include <string.h>
14 #include <vector>
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)
27 const char* kUsage =
28 "Usage: gensyscallinfos <header> <syscall infos> <syscall types sizes>\n"
29 "\n"
30 "Given the (preprocessed) header file that defines the syscall prototypes "
31 "the\n"
32 "command generates a source file consisting of syscall infos, which is "
33 "needed\n"
34 "to build gensyscalls, which in turn generates the assembly syscall\n"
35 "definitions and code for the kernelland syscall dispatcher.\n"
36 "\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 "
40 "to\n"
41 " build gensyscalls.\n"
42 " <syscall types sizes> - Output: A source file that will by another "
43 "build\n"
44 " step turned into a header file included by\n"
45 " <syscall infos>.\n";
48 static void
49 print_usage(bool error)
51 fprintf((error ? stderr : stdout), kUsage);
55 struct Type {
56 Type(const char* type) : type(type) {}
57 Type(const string& type) : type(type) {}
59 string 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) {}
69 string name;
73 class Function {
74 public:
75 Function() : fReturnType("") {}
77 void SetName(const string& name)
79 fName = name;
82 const string& GetName() const
84 return fName;
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)
104 fReturnType = type;
107 const Type& GetReturnType() const
109 return fReturnType;
112 protected:
113 string fName;
114 vector<NamedType> fParameters;
115 Type fReturnType;
119 class Syscall : public Function {
120 public:
121 string GetKernelName() const
123 int baseIndex = 0;
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));
130 return kernelName;
135 class Tokenizer {
136 public:
137 Tokenizer(istream& input)
138 : fInput(input),
139 fHasCurrent(false)
143 string GetCurrentToken()
145 if (!fHasCurrent)
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)
162 if (fHasCurrent) {
163 fTokens.pop_front();
164 fHasCurrent = false;
166 while (fTokens.empty())
167 _ReadLine();
168 fHasCurrent = true;
169 if (skippedTokens)
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)
185 GetNextToken();
186 ExpectToken(expectedToken);
189 bool CheckToken(const string& expectedToken)
191 string token = GetCurrentToken();
192 return (expectedToken == token);
195 bool CheckNextToken(const string& expectedToken)
197 GetNextToken();
198 bool result = CheckToken(expectedToken);
199 if (!result)
200 PutCurrentToken();
201 return result;
204 void PutCurrentToken()
206 if (!fHasCurrent)
207 throw Exception("GetCurrentToken(): No current token!");
208 fHasCurrent = false;
211 void PutToken(string token)
213 if (fHasCurrent) {
214 fTokens.pop_front();
215 fHasCurrent = false;
217 fTokens.push_front(token);
220 void PutTokens(stack<string>& tokens)
222 if (fHasCurrent) {
223 fTokens.pop_front();
224 fHasCurrent = false;
226 while (!tokens.empty()) {
227 fTokens.push_front(tokens.top());
228 tokens.pop();
232 private:
233 void _ReadLine()
235 // read the line
236 char buffer[10240];
237 if (!fInput.getline(buffer, sizeof(buffer)))
238 throw EOFException("Unexpected end of input.");
239 // parse it
240 vector<string> line;
241 int len = strlen(buffer);
242 int tokenStart = 0;
243 for (int i = 0; i < len; i++) {
244 char c = buffer[i];
245 if (isspace(c)) {
246 if (tokenStart < i)
247 line.push_back(string(buffer + tokenStart, buffer + i));
248 tokenStart = i + 1;
249 continue;
251 switch (buffer[i]) {
252 case '#':
253 case '(':
254 case ')':
255 case '*':
256 case '&':
257 case '[':
258 case ']':
259 case ';':
260 case ',':
261 if (tokenStart < i) {
262 line.push_back(string(buffer + tokenStart,
263 buffer + i));
265 line.push_back(string(buffer + i, buffer + i + 1));
266 tokenStart = i + 1;
267 break;
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]))
276 return;
278 for (int i = 0; i < (int)line.size(); i++)
279 fTokens.push_back(line[i]);
282 private:
283 istream& fInput;
284 list<string> fTokens;
285 bool fHasCurrent;
289 class Main {
290 public:
292 int Run(int argc, char** argv)
294 // parse parameters
295 if (argc >= 2
296 && (string(argv[1]) == "-h" || string(argv[1]) == "--help")) {
297 print_usage(false);
298 return 0;
300 if (argc != 4) {
301 print_usage(true);
302 return 1;
304 _ParseSyscalls(argv[1]);
305 _WriteSyscallInfoFile(argv[2]);
306 _WriteSyscallTypeSizes(argv[3]);
307 return 0;
310 private:
311 void _ParseSyscalls(const char* filename)
313 // open the input file
314 ifstream file(filename, ifstream::in);
315 if (!file.is_open())
316 throw new IOException(string("Failed to open `") + filename + "'.");
317 // parse the syscalls
318 Tokenizer tokenizer(file);
319 // find "#pragma syscalls begin"
320 while (true) {
321 while (tokenizer.GetNextToken() != "#");
322 stack<string> skippedTokens;
323 if (tokenizer.GetNextToken(skippedTokens) == "pragma"
324 && tokenizer.GetNextToken(skippedTokens) == "syscalls"
325 && tokenizer.GetNextToken(skippedTokens) == "begin") {
326 break;
328 tokenizer.PutTokens(skippedTokens);
330 // parse the functions
331 while (!tokenizer.CheckNextToken("#")) {
332 Syscall syscall;
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);
346 if (!file.is_open())
347 throw new IOException(string("Failed to open `") + filename + "'.");
349 // write preamble
350 file << "#include \"gensyscalls.h\"" << endl;
351 file << "#include \"syscall_types_sizes.h\"" << endl;
352 file << endl;
354 file << "const char* const kReturnTypeAlignmentType = \""
355 EVAL_MACRO(MAKE_STRING, SYSCALL_RETURN_TYPE_ALIGNMENT_TYPE)
356 << "\";" << endl;
357 file << "const char* const kParameterAlignmentType = \""
358 EVAL_MACRO(MAKE_STRING, SYSCALL_PARAMETER_ALIGNMENT_TYPE)
359 << "\";" << endl;
360 file << "const int kReturnTypeAlignmentSize = "
361 "SYSCALL_RETURN_TYPE_ALIGNMENT_SIZE;" << endl;
362 file << "const int kParameterAlignmentSize = "
363 "SYSCALL_PARAMETER_ALIGNMENT_SIZE;" << endl;
364 file << endl;
366 file << "SyscallVector* create_syscall_vector() {" << endl;
367 file << "\tSyscallVector* syscallVector = SyscallVector::Create();"
368 << endl;
369 file << "\tSyscall* syscall;" << endl;
371 // syscalls
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>,
384 // "returnType");
385 file << "\tsyscall->SetReturnType("
386 << "SYSCALL_RETURN_TYPE_SIZE_" << i << ", \""
387 << returnType.type << "\");" << endl;
389 // parameters
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 << "\");"
398 << endl;
400 file << endl;
403 // postamble
404 file << "\treturn syscallVector;" << endl;
405 file << "}" << endl;
408 void _WriteSyscallTypeSizes(const char* filename)
410 // open the syscall info file
411 ofstream file(filename, ofstream::out | ofstream::trunc);
412 if (!file.is_open())
413 throw new IOException(string("Failed to open `") + filename + "'.");
415 // write preamble
416 file << "#include <computed_asm_macros.h>" << endl;
417 file << "#include <syscalls.h>" << endl;
418 file << endl;
419 file << "#include \"arch_gensyscalls.h\"" << endl;
420 file << 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;
427 file << endl;
429 // syscalls
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;
437 } else {
438 file << "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_RETURN_TYPE_SIZE_"
439 << i << ", sizeof(" << returnType.type << "));" << endl;
442 // parameters
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;
449 file << endl;
452 // postamble
453 file << "}" << 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 "
468 "return type.");
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);
478 // get arguments
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)
491 vector<string> type;
492 while (tokenizer.GetNextToken() != ")"
493 && tokenizer.GetCurrentToken() != ",") {
494 string token = tokenizer.GetCurrentToken();
495 type.push_back(token);
496 if (token == "(") {
497 // This must be a function pointer. We deal with that in a
498 // separate method.
499 _ParseFunctionPointerParameter(tokenizer, syscall, type);
500 return;
503 tokenizer.PutCurrentToken();
504 if (type.size() < 2) {
505 if (type.size() == 1 && type[0] == "void") {
506 // that's OK
507 return;
509 throw ParseException("Error while parsing function parameter.");
512 // last component is the parameter name
513 string typeName = type.back();
514 type.pop_back();
516 string typeString(type[0]);
517 for (int i = 1; i < (int)type.size(); i++) {
518 typeString += " ";
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
529 // vector.
530 if (type.size() < 2) {
531 throw ParseException("Error parsing function parameter. "
532 "No return type.");
534 // read all the "*"s there are
535 while (tokenizer.CheckNextToken("*"))
536 type.push_back("*");
537 // now comes the parameter name, if specified -- skip it
538 string typeName;
539 if (!tokenizer.CheckNextToken(")")) {
540 typeName = tokenizer.GetNextToken();
541 tokenizer.ExpectNextToken(")");
542 } else {
543 throw ParseException("Error while parsing function parameter. "
544 "No parameter name.");
546 type.push_back(")");
547 // the function parameters
548 tokenizer.ExpectNextToken("(");
549 type.push_back("(");
550 while (!tokenizer.CheckNextToken(")"))
551 type.push_back(tokenizer.GetNextToken());
552 type.push_back(")");
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++) {
556 typeString += " ";
557 typeString += type[i];
559 syscall.AddParameter(NamedType(typeString, typeName));
562 private:
563 vector<Syscall> fSyscalls;
568 main(int argc, char** argv)
570 try {
571 return Main().Run(argc, argv);
572 } catch (Exception& exception) {
573 fprintf(stderr, "%s\n", exception.what());
574 return 1;