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 53 print_usage(bool error) 54 { 55 fputs(kUsage, (error ? stderr : stdout)); 56 } 57 58 59 struct Type { 60 Type(const char* type) : type(type) {} 61 Type(const string& type) : type(type) {} 62 63 string type; 64 }; 65 66 67 struct NamedType : Type { 68 NamedType(const char* type, const char* name) 69 : Type(type), name(name) {} 70 NamedType(const string& type, const string& name) 71 : Type(type), name(name) {} 72 73 string name; 74 }; 75 76 77 class Function { 78 public: 79 Function() : fReturnType("") {} 80 81 void SetName(const string& name) 82 { 83 fName = name; 84 } 85 86 const string& GetName() const 87 { 88 return fName; 89 } 90 91 void AddParameter(const NamedType& type) 92 { 93 fParameters.push_back(type); 94 } 95 96 int CountParameters() const 97 { 98 return fParameters.size(); 99 } 100 101 const NamedType& ParameterAt(int index) const 102 { 103 return fParameters[index]; 104 } 105 106 void SetReturnType(const Type& type) 107 { 108 fReturnType = type; 109 } 110 111 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: 125 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: 141 Tokenizer(istream& input) 142 : fInput(input), 143 fHasCurrent(false) 144 { 145 } 146 147 string GetCurrentToken() 148 { 149 if (!fHasCurrent) 150 throw Exception("GetCurrentToken(): No current token!"); 151 return fTokens.front(); 152 } 153 154 string GetNextToken() 155 { 156 return GetNextToken(NULL); 157 } 158 159 string GetNextToken(stack<string>& skippedTokens) 160 { 161 return GetNextToken(&skippedTokens); 162 } 163 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 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 187 void ExpectNextToken(const string& expectedToken) 188 { 189 GetNextToken(); 190 ExpectToken(expectedToken); 191 } 192 193 bool CheckToken(const string& expectedToken) 194 { 195 string token = GetCurrentToken(); 196 return (expectedToken == token); 197 } 198 199 bool CheckNextToken(const string& expectedToken) 200 { 201 GetNextToken(); 202 bool result = CheckToken(expectedToken); 203 if (!result) 204 PutCurrentToken(); 205 return result; 206 } 207 208 void PutCurrentToken() 209 { 210 if (!fHasCurrent) 211 throw Exception("GetCurrentToken(): No current token!"); 212 fHasCurrent = false; 213 } 214 215 void PutToken(string token) 216 { 217 if (fHasCurrent) { 218 fTokens.pop_front(); 219 fHasCurrent = false; 220 } 221 fTokens.push_front(token); 222 } 223 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: 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 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: 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 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 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 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 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 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 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