1 /*
2 * Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
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>
15
16 #include "gensyscalls_common.h"
17
18 #include "arch_gensyscalls.h"
19 // for the alignment type macros (only for the type names)
20
21 #ifndef SYSCALL_LONG_PARAMETER_ALIGNMENT_TYPE
22 #define SYSCALL_LONG_PARAMETER_ALIGNMENT_TYPE SYSCALL_PARAMETER_ALIGNMENT_TYPE
23 #endif
24
25
26 // macro trickery to create a string literal
27 #define MAKE_STRING(x) #x
28 #define EVAL_MACRO(macro, x) macro(x)
29
30
31 const char* kUsage =
32 "Usage: gensyscallinfos <header> <syscall infos> <syscall types sizes>\n"
33 "\n"
34 "Given the (preprocessed) header file that defines the syscall prototypes "
35 "the\n"
36 "command generates a source file consisting of syscall infos, which is "
37 "needed\n"
38 "to build gensyscalls, which in turn generates the assembly syscall\n"
39 "definitions and code for the kernelland syscall dispatcher.\n"
40 "\n"
41 " <header> - Input: The preprocessed header file with the\n"
42 " syscall prototypes.\n"
43 " <syscall infos> - Output: The syscall infos source file needed "
44 "to\n"
45 " build gensyscalls.\n"
46 " <syscall types sizes> - Output: A source file that will by another "
47 "build\n"
48 " step turned into a header file included by\n"
49 " <syscall infos>.\n";
50
51
52 static void
print_usage(bool error)53 print_usage(bool error)
54 {
55 fputs(kUsage, (error ? stderr : stdout));
56 }
57
58
59 struct Type {
TypeType60 Type(const char* type) : type(type) {}
TypeType61 Type(const string& type) : type(type) {}
62
63 string type;
64 };
65
66
67 struct NamedType : Type {
NamedTypeNamedType68 NamedType(const char* type, const char* name)
69 : Type(type), name(name) {}
NamedTypeNamedType70 NamedType(const string& type, const string& name)
71 : Type(type), name(name) {}
72
73 string name;
74 };
75
76
77 class Function {
78 public:
Function()79 Function() : fReturnType("") {}
80
SetName(const string & name)81 void SetName(const string& name)
82 {
83 fName = name;
84 }
85
GetName() const86 const string& GetName() const
87 {
88 return fName;
89 }
90
AddParameter(const NamedType & type)91 void AddParameter(const NamedType& type)
92 {
93 fParameters.push_back(type);
94 }
95
CountParameters() const96 int CountParameters() const
97 {
98 return fParameters.size();
99 }
100
ParameterAt(int index) const101 const NamedType& ParameterAt(int index) const
102 {
103 return fParameters[index];
104 }
105
SetReturnType(const Type & type)106 void SetReturnType(const Type& type)
107 {
108 fReturnType = type;
109 }
110
GetReturnType() const111 const Type& GetReturnType() const
112 {
113 return fReturnType;
114 }
115
116 protected:
117 string fName;
118 vector<NamedType> fParameters;
119 Type fReturnType;
120 };
121
122
123 class Syscall : public Function {
124 public:
GetKernelName() const125 string GetKernelName() const
126 {
127 int baseIndex = 0;
128 if (fName.find("_kern_") == 0)
129 baseIndex = strlen("_kern_");
130 else if (fName.find("sys_") == 0)
131 baseIndex = strlen("sys_");
132 string kernelName("_user_");
133 kernelName.append(string(fName, baseIndex));
134 return kernelName;
135 }
136 };
137
138
139 class Tokenizer {
140 public:
Tokenizer(istream & input)141 Tokenizer(istream& input)
142 : fInput(input),
143 fHasCurrent(false)
144 {
145 }
146
GetCurrentToken()147 string GetCurrentToken()
148 {
149 if (!fHasCurrent)
150 throw Exception("GetCurrentToken(): No current token!");
151 return fTokens.front();
152 }
153
GetNextToken()154 string GetNextToken()
155 {
156 return GetNextToken(NULL);
157 }
158
GetNextToken(stack<string> & skippedTokens)159 string GetNextToken(stack<string>& skippedTokens)
160 {
161 return GetNextToken(&skippedTokens);
162 }
163
GetNextToken(stack<string> * skippedTokens)164 string GetNextToken(stack<string>* skippedTokens)
165 {
166 if (fHasCurrent) {
167 fTokens.pop_front();
168 fHasCurrent = false;
169 }
170 while (fTokens.empty())
171 _ReadLine();
172 fHasCurrent = true;
173 if (skippedTokens)
174 skippedTokens->push(fTokens.front());
175 return fTokens.front();
176 }
177
ExpectToken(const string & expectedToken)178 void ExpectToken(const string& expectedToken)
179 {
180 string token = GetCurrentToken();
181 if (expectedToken != token) {
182 throw ParseException(string("Unexpected token `") + token
183 + "'. Expected was `" + expectedToken + "'.");
184 }
185 }
186
ExpectNextToken(const string & expectedToken)187 void ExpectNextToken(const string& expectedToken)
188 {
189 GetNextToken();
190 ExpectToken(expectedToken);
191 }
192
CheckToken(const string & expectedToken)193 bool CheckToken(const string& expectedToken)
194 {
195 string token = GetCurrentToken();
196 return (expectedToken == token);
197 }
198
CheckNextToken(const string & expectedToken)199 bool CheckNextToken(const string& expectedToken)
200 {
201 GetNextToken();
202 bool result = CheckToken(expectedToken);
203 if (!result)
204 PutCurrentToken();
205 return result;
206 }
207
PutCurrentToken()208 void PutCurrentToken()
209 {
210 if (!fHasCurrent)
211 throw Exception("GetCurrentToken(): No current token!");
212 fHasCurrent = false;
213 }
214
PutToken(string token)215 void PutToken(string token)
216 {
217 if (fHasCurrent) {
218 fTokens.pop_front();
219 fHasCurrent = false;
220 }
221 fTokens.push_front(token);
222 }
223
PutTokens(stack<string> & tokens)224 void PutTokens(stack<string>& tokens)
225 {
226 if (fHasCurrent) {
227 fTokens.pop_front();
228 fHasCurrent = false;
229 }
230 while (!tokens.empty()) {
231 fTokens.push_front(tokens.top());
232 tokens.pop();
233 }
234 }
235
236 private:
_ReadLine()237 void _ReadLine()
238 {
239 // read the line
240 char buffer[10240];
241 if (!fInput.getline(buffer, sizeof(buffer)))
242 throw EOFException("Unexpected end of input.");
243 // parse it
244 vector<string> line;
245 int len = strlen(buffer);
246 int tokenStart = 0;
247 for (int i = 0; i < len; i++) {
248 char c = buffer[i];
249 if (isspace(c)) {
250 if (tokenStart < i)
251 line.push_back(string(buffer + tokenStart, buffer + i));
252 tokenStart = i + 1;
253 continue;
254 }
255 switch (buffer[i]) {
256 case '#':
257 case '(':
258 case ')':
259 case '*':
260 case '&':
261 case '[':
262 case ']':
263 case ';':
264 case ',':
265 if (tokenStart < i) {
266 line.push_back(string(buffer + tokenStart,
267 buffer + i));
268 }
269 line.push_back(string(buffer + i, buffer + i + 1));
270 tokenStart = i + 1;
271 break;
272 }
273 }
274 if (tokenStart < len)
275 line.push_back(string(buffer + tokenStart, buffer + len));
276 // drop the line, if it starts with "# <number>", as those are
277 // directions from the pre-processor to the compiler
278 if (line.size() >= 2) {
279 if (line[0] == "#" && isdigit(line[1][0]))
280 return;
281 }
282 for (int i = 0; i < (int)line.size(); i++)
283 fTokens.push_back(line[i]);
284 }
285
286 private:
287 istream& fInput;
288 list<string> fTokens;
289 bool fHasCurrent;
290 };
291
292
293 class Main {
294 public:
295
Run(int argc,char ** argv)296 int Run(int argc, char** argv)
297 {
298 // parse parameters
299 if (argc >= 2
300 && (string(argv[1]) == "-h" || string(argv[1]) == "--help")) {
301 print_usage(false);
302 return 0;
303 }
304 if (argc != 4) {
305 print_usage(true);
306 return 1;
307 }
308 _ParseSyscalls(argv[1]);
309 _WriteSyscallInfoFile(argv[2]);
310 _WriteSyscallTypeSizes(argv[3]);
311 return 0;
312 }
313
314 private:
_ParseSyscalls(const char * filename)315 void _ParseSyscalls(const char* filename)
316 {
317 // open the input file
318 ifstream file(filename, ifstream::in);
319 if (!file.is_open())
320 throw IOException(string("Failed to open `") + filename + "'.");
321 // parse the syscalls
322 Tokenizer tokenizer(file);
323 // find "#pragma syscalls begin"
324 while (true) {
325 while (tokenizer.GetNextToken() != "#");
326 stack<string> skippedTokens;
327 if (tokenizer.GetNextToken(skippedTokens) == "pragma"
328 && tokenizer.GetNextToken(skippedTokens) == "syscalls"
329 && tokenizer.GetNextToken(skippedTokens) == "begin") {
330 break;
331 }
332 tokenizer.PutTokens(skippedTokens);
333 }
334 // parse the functions
335 while (!tokenizer.CheckNextToken("#")) {
336 Syscall syscall;
337 _ParseSyscall(tokenizer, syscall);
338 fSyscalls.push_back(syscall);
339 }
340 // expect "pragma syscalls end"
341 tokenizer.ExpectNextToken("pragma");
342 tokenizer.ExpectNextToken("syscalls");
343 tokenizer.ExpectNextToken("end");
344 }
345
_WriteSyscallInfoFile(const char * filename)346 void _WriteSyscallInfoFile(const char* filename)
347 {
348 // open the syscall info file
349 ofstream file(filename, ofstream::out | ofstream::trunc);
350 if (!file.is_open())
351 throw IOException(string("Failed to open `") + filename + "'.");
352
353 // write preamble
354 file << "#include \"gensyscalls.h\"" << endl;
355 file << "#include \"syscall_types_sizes.h\"" << endl;
356 file << endl;
357
358 file << "const char* const kReturnTypeAlignmentType = \""
359 EVAL_MACRO(MAKE_STRING, SYSCALL_RETURN_TYPE_ALIGNMENT_TYPE)
360 << "\";" << endl;
361 file << "const char* const kParameterAlignmentType = \""
362 EVAL_MACRO(MAKE_STRING, SYSCALL_PARAMETER_ALIGNMENT_TYPE)
363 << "\";" << endl;
364 file << "const char* const kLongParameterAlignmentType = \""
365 EVAL_MACRO(MAKE_STRING, SYSCALL_LONG_PARAMETER_ALIGNMENT_TYPE)
366 << "\";" << endl;
367 file << "const int kReturnTypeAlignmentSize = "
368 "SYSCALL_RETURN_TYPE_ALIGNMENT_SIZE;" << endl;
369 file << "const int kParameterAlignmentSize = "
370 "SYSCALL_PARAMETER_ALIGNMENT_SIZE;" << endl;
371 file << "const int kLongParameterAlignmentSize = "
372 "SYSCALL_LONG_PARAMETER_ALIGNMENT_SIZE;" << endl;
373 file << endl;
374
375 file << "SyscallVector* create_syscall_vector() {" << endl;
376 file << "\tSyscallVector* syscallVector = SyscallVector::Create();"
377 << endl;
378 file << "\tSyscall* syscall;" << endl;
379
380 // syscalls
381 for (int i = 0; i < (int)fSyscalls.size(); i++) {
382 const Syscall& syscall = fSyscalls[i];
383
384 // syscall = syscallVector->CreateSyscall("syscallName",
385 // "syscallKernelName");
386 file << "\tsyscall = syscallVector->CreateSyscall(\""
387 << syscall.GetName() << "\", \""
388 << syscall.GetKernelName() << "\");" << endl;
389
390 const Type& returnType = syscall.GetReturnType();
391
392 // syscall->SetReturnType<(SYSCALL_RETURN_TYPE_SIZE_<i>,
393 // "returnType");
394 file << "\tsyscall->SetReturnType("
395 << "SYSCALL_RETURN_TYPE_SIZE_" << i << ", \""
396 << returnType.type << "\");" << endl;
397
398 // parameters
399 int paramCount = syscall.CountParameters();
400 for (int k = 0; k < paramCount; k++) {
401 const NamedType& param = syscall.ParameterAt(k);
402 // syscall->AddParameter(SYSCALL_PARAMETER_SIZE_<i>_<k>,
403 // "parameterTypeName", "parameterName");
404 file << "\tsyscall->AddParameter("
405 << "SYSCALL_PARAMETER_SIZE_" << i << "_" << k
406 << ", \"" << param.type << "\", \"" << param.name << "\");"
407 << endl;
408 }
409 file << endl;
410 }
411
412 // postamble
413 file << "\treturn syscallVector;" << endl;
414 file << "}" << endl;
415 }
416
_WriteSyscallTypeSizes(const char * filename)417 void _WriteSyscallTypeSizes(const char* filename)
418 {
419 // open the syscall info file
420 ofstream file(filename, ofstream::out | ofstream::trunc);
421 if (!file.is_open())
422 throw IOException(string("Failed to open `") + filename + "'.");
423
424 // write preamble
425 file << "#include <computed_asm_macros.h>" << endl;
426 file << "#include <syscalls.h>" << endl;
427 file << endl;
428 file << "#include \"arch_gensyscalls.h\"" << endl;
429 file << endl;
430 file << "#ifndef SYSCALL_LONG_PARAMETER_ALIGNMENT_TYPE" << endl;
431 file << "#define SYSCALL_LONG_PARAMETER_ALIGNMENT_TYPE SYSCALL_PARAMETER_ALIGNMENT_TYPE"
432 << endl;
433 file << "#endif" << endl;
434 file << "void dummy() {" << endl;
435
436 file << "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_RETURN_TYPE_ALIGNMENT_SIZE, "
437 "sizeof(SYSCALL_RETURN_TYPE_ALIGNMENT_TYPE));" << endl;
438 file << "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_PARAMETER_ALIGNMENT_SIZE, "
439 "sizeof(SYSCALL_PARAMETER_ALIGNMENT_TYPE));" << endl;
440 file << "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_LONG_PARAMETER_ALIGNMENT_SIZE, "
441 "sizeof(SYSCALL_LONG_PARAMETER_ALIGNMENT_TYPE));" << endl;
442 file << endl;
443
444 // syscalls
445 for (int i = 0; i < (int)fSyscalls.size(); i++) {
446 const Syscall& syscall = fSyscalls[i];
447 const Type& returnType = syscall.GetReturnType();
448
449 if (returnType.type == "void") {
450 file << "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_RETURN_TYPE_SIZE_"
451 << i << ", 0);" << endl;
452 } else {
453 file << "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_RETURN_TYPE_SIZE_"
454 << i << ", sizeof(" << returnType.type << "));" << endl;
455 }
456
457 // parameters
458 int paramCount = syscall.CountParameters();
459 for (int k = 0; k < paramCount; k++) {
460 const NamedType& param = syscall.ParameterAt(k);
461 file << "DEFINE_COMPUTED_ASM_MACRO(SYSCALL_PARAMETER_SIZE_" << i
462 << "_" << k << ", sizeof(" << param.type << "));" << endl;
463 }
464 file << endl;
465 }
466
467 // postamble
468 file << "}" << endl;
469 }
470
_ParseSyscall(Tokenizer & tokenizer,Syscall & syscall)471 void _ParseSyscall(Tokenizer& tokenizer, Syscall& syscall)
472 {
473 // get return type and function name
474 vector<string> returnType;
475 while (tokenizer.GetNextToken() != "(") {
476 string token = tokenizer.GetCurrentToken();
477 // strip leading "extern"
478 if (!returnType.empty() || token != "extern")
479 returnType.push_back(token);
480 }
481 if (returnType.size() < 2) {
482 throw ParseException("Error while parsing function "
483 "return type.");
484 }
485 syscall.SetName(returnType[returnType.size() - 1]);
486 returnType.pop_back();
487 string returnTypeString(returnType[0]);
488 for (int i = 1; i < (int)returnType.size(); i++) {
489 returnTypeString += " ";
490 returnTypeString += returnType[i];
491 }
492 syscall.SetReturnType(returnTypeString);
493 // get arguments
494 if (!tokenizer.CheckNextToken(")")) {
495 _ParseParameter(tokenizer, syscall);
496 while (!tokenizer.CheckNextToken(")")) {
497 tokenizer.ExpectNextToken(",");
498 _ParseParameter(tokenizer, syscall);
499 }
500 }
501 tokenizer.ExpectNextToken(";");
502 }
503
_ParseParameter(Tokenizer & tokenizer,Syscall & syscall)504 void _ParseParameter(Tokenizer& tokenizer, Syscall& syscall)
505 {
506 vector<string> type;
507 while (tokenizer.GetNextToken() != ")"
508 && tokenizer.GetCurrentToken() != ",") {
509 string token = tokenizer.GetCurrentToken();
510 type.push_back(token);
511 if (token == "(") {
512 // This must be a function pointer. We deal with that in a
513 // separate method.
514 _ParseFunctionPointerParameter(tokenizer, syscall, type);
515 return;
516 }
517 }
518 tokenizer.PutCurrentToken();
519 if (type.size() < 2) {
520 if (type.size() == 1 && type[0] == "void") {
521 // that's OK
522 return;
523 }
524 throw ParseException("Error while parsing function parameter.");
525 }
526
527 // last component is the parameter name
528 string typeName = type.back();
529 type.pop_back();
530
531 string typeString(type[0]);
532 for (int i = 1; i < (int)type.size(); i++) {
533 typeString += " ";
534 typeString += type[i];
535 }
536 syscall.AddParameter(NamedType(typeString, typeName));
537 }
538
_ParseFunctionPointerParameter(Tokenizer & tokenizer,Syscall & syscall,vector<string> & type)539 void _ParseFunctionPointerParameter(Tokenizer& tokenizer, Syscall& syscall,
540 vector<string>& type)
541 {
542 // When this method is entered, the return type and the opening
543 // parenthesis must already be parse and stored in the supplied type
544 // vector.
545 if (type.size() < 2) {
546 throw ParseException("Error parsing function parameter. "
547 "No return type.");
548 }
549 // read all the "*"s there are
550 while (tokenizer.CheckNextToken("*"))
551 type.push_back("*");
552 // now comes the parameter name, if specified -- skip it
553 string typeName;
554 if (!tokenizer.CheckNextToken(")")) {
555 typeName = tokenizer.GetNextToken();
556 tokenizer.ExpectNextToken(")");
557 } else {
558 throw ParseException("Error while parsing function parameter. "
559 "No parameter name.");
560 }
561 type.push_back(")");
562 // the function parameters
563 tokenizer.ExpectNextToken("(");
564 type.push_back("(");
565 while (!tokenizer.CheckNextToken(")"))
566 type.push_back(tokenizer.GetNextToken());
567 type.push_back(")");
568 // compose the type string and add it to the syscall parameters
569 string typeString(type[0]);
570 for (int i = 1; i < (int)type.size(); i++) {
571 typeString += " ";
572 typeString += type[i];
573 }
574 syscall.AddParameter(NamedType(typeString, typeName));
575 }
576
577 private:
578 vector<Syscall> fSyscalls;
579 };
580
581
582 int
main(int argc,char ** argv)583 main(int argc, char** argv)
584 {
585 try {
586 return Main().Run(argc, argv);
587 } catch (const Exception& exception) {
588 fprintf(stderr, "%s\n", exception.what());
589 return 1;
590 }
591 }
592