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 22 // macro trickery to create a string literal 23 #define MAKE_STRING(x) #x 24 #define EVAL_MACRO(macro, x) macro(x) 25 26 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"; 46 47 48 static void 49 print_usage(bool error) 50 { 51 fprintf((error ? stderr : stdout), kUsage); 52 } 53 54 55 struct Type { 56 Type(const char* type) : type(type) {} 57 Type(const string& type) : type(type) {} 58 59 string type; 60 }; 61 62 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) {} 68 69 string name; 70 }; 71 72 73 class Function { 74 public: 75 Function() : fReturnType("") {} 76 77 void SetName(const string& name) 78 { 79 fName = name; 80 } 81 82 const string& GetName() const 83 { 84 return fName; 85 } 86 87 void AddParameter(const NamedType& type) 88 { 89 fParameters.push_back(type); 90 } 91 92 int CountParameters() const 93 { 94 return fParameters.size(); 95 } 96 97 const NamedType& ParameterAt(int index) const 98 { 99 return fParameters[index]; 100 } 101 102 void SetReturnType(const Type& type) 103 { 104 fReturnType = type; 105 } 106 107 const Type& GetReturnType() const 108 { 109 return fReturnType; 110 } 111 112 protected: 113 string fName; 114 vector<NamedType> fParameters; 115 Type fReturnType; 116 }; 117 118 119 class Syscall : public Function { 120 public: 121 string GetKernelName() const 122 { 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; 131 } 132 }; 133 134 135 class Tokenizer { 136 public: 137 Tokenizer(istream& input) 138 : fInput(input), 139 fHasCurrent(false) 140 { 141 } 142 143 string GetCurrentToken() 144 { 145 if (!fHasCurrent) 146 throw Exception("GetCurrentToken(): No current token!"); 147 return fTokens.front(); 148 } 149 150 string GetNextToken() 151 { 152 return GetNextToken(NULL); 153 } 154 155 string GetNextToken(stack<string>& skippedTokens) 156 { 157 return GetNextToken(&skippedTokens); 158 } 159 160 string GetNextToken(stack<string>* skippedTokens) 161 { 162 if (fHasCurrent) { 163 fTokens.pop_front(); 164 fHasCurrent = false; 165 } 166 while (fTokens.empty()) 167 _ReadLine(); 168 fHasCurrent = true; 169 if (skippedTokens) 170 skippedTokens->push(fTokens.front()); 171 return fTokens.front(); 172 } 173 174 void ExpectToken(const string& expectedToken) 175 { 176 string token = GetCurrentToken(); 177 if (expectedToken != token) { 178 throw ParseException(string("Unexpected token `") + token 179 + "'. Expected was `" + expectedToken + "'."); 180 } 181 } 182 183 void ExpectNextToken(const string& expectedToken) 184 { 185 GetNextToken(); 186 ExpectToken(expectedToken); 187 } 188 189 bool CheckToken(const string& expectedToken) 190 { 191 string token = GetCurrentToken(); 192 return (expectedToken == token); 193 } 194 195 bool CheckNextToken(const string& expectedToken) 196 { 197 GetNextToken(); 198 bool result = CheckToken(expectedToken); 199 if (!result) 200 PutCurrentToken(); 201 return result; 202 } 203 204 void PutCurrentToken() 205 { 206 if (!fHasCurrent) 207 throw Exception("GetCurrentToken(): No current token!"); 208 fHasCurrent = false; 209 } 210 211 void PutToken(string token) 212 { 213 if (fHasCurrent) { 214 fTokens.pop_front(); 215 fHasCurrent = false; 216 } 217 fTokens.push_front(token); 218 } 219 220 void PutTokens(stack<string>& tokens) 221 { 222 if (fHasCurrent) { 223 fTokens.pop_front(); 224 fHasCurrent = false; 225 } 226 while (!tokens.empty()) { 227 fTokens.push_front(tokens.top()); 228 tokens.pop(); 229 } 230 } 231 232 private: 233 void _ReadLine() 234 { 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; 250 } 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)); 264 } 265 line.push_back(string(buffer + i, buffer + i + 1)); 266 tokenStart = i + 1; 267 break; 268 } 269 } 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; 277 } 278 for (int i = 0; i < (int)line.size(); i++) 279 fTokens.push_back(line[i]); 280 } 281 282 private: 283 istream& fInput; 284 list<string> fTokens; 285 bool fHasCurrent; 286 }; 287 288 289 class Main { 290 public: 291 292 int Run(int argc, char** argv) 293 { 294 // parse parameters 295 if (argc >= 2 296 && (string(argv[1]) == "-h" || string(argv[1]) == "--help")) { 297 print_usage(false); 298 return 0; 299 } 300 if (argc != 4) { 301 print_usage(true); 302 return 1; 303 } 304 _ParseSyscalls(argv[1]); 305 _WriteSyscallInfoFile(argv[2]); 306 _WriteSyscallTypeSizes(argv[3]); 307 return 0; 308 } 309 310 private: 311 void _ParseSyscalls(const char* filename) 312 { 313 // open the input file 314 ifstream file(filename, ifstream::in); 315 if (!file.is_open()) 316 throw 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; 327 } 328 tokenizer.PutTokens(skippedTokens); 329 } 330 // parse the functions 331 while (!tokenizer.CheckNextToken("#")) { 332 Syscall syscall; 333 _ParseSyscall(tokenizer, syscall); 334 fSyscalls.push_back(syscall); 335 } 336 // expect "pragma syscalls end" 337 tokenizer.ExpectNextToken("pragma"); 338 tokenizer.ExpectNextToken("syscalls"); 339 tokenizer.ExpectNextToken("end"); 340 } 341 342 void _WriteSyscallInfoFile(const char* filename) 343 { 344 // open the syscall info file 345 ofstream file(filename, ofstream::out | ofstream::trunc); 346 if (!file.is_open()) 347 throw IOException(string("Failed to open `") + filename + "'."); 348 349 // write preamble 350 file << "#include \"gensyscalls.h\"" << endl; 351 file << "#include \"syscall_types_sizes.h\"" << endl; 352 file << endl; 353 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; 365 366 file << "SyscallVector* create_syscall_vector() {" << endl; 367 file << "\tSyscallVector* syscallVector = SyscallVector::Create();" 368 << endl; 369 file << "\tSyscall* syscall;" << endl; 370 371 // syscalls 372 for (int i = 0; i < (int)fSyscalls.size(); i++) { 373 const Syscall& syscall = fSyscalls[i]; 374 375 // syscall = syscallVector->CreateSyscall("syscallName", 376 // "syscallKernelName"); 377 file << "\tsyscall = syscallVector->CreateSyscall(\"" 378 << syscall.GetName() << "\", \"" 379 << syscall.GetKernelName() << "\");" << endl; 380 381 const Type& returnType = syscall.GetReturnType(); 382 383 // syscall->SetReturnType<(SYSCALL_RETURN_TYPE_SIZE_<i>, 384 // "returnType"); 385 file << "\tsyscall->SetReturnType(" 386 << "SYSCALL_RETURN_TYPE_SIZE_" << i << ", \"" 387 << returnType.type << "\");" << endl; 388 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; 399 } 400 file << endl; 401 } 402 403 // postamble 404 file << "\treturn syscallVector;" << endl; 405 file << "}" << endl; 406 } 407 408 void _WriteSyscallTypeSizes(const char* filename) 409 { 410 // open the syscall info file 411 ofstream file(filename, ofstream::out | ofstream::trunc); 412 if (!file.is_open()) 413 throw IOException(string("Failed to open `") + filename + "'."); 414 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; 422 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; 428 429 // syscalls 430 for (int i = 0; i < (int)fSyscalls.size(); i++) { 431 const Syscall& syscall = fSyscalls[i]; 432 const Type& returnType = syscall.GetReturnType(); 433 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; 440 } 441 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; 448 } 449 file << endl; 450 } 451 452 // postamble 453 file << "}" << endl; 454 } 455 456 void _ParseSyscall(Tokenizer& tokenizer, Syscall& syscall) 457 { 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); 465 } 466 if (returnType.size() < 2) { 467 throw ParseException("Error while parsing function " 468 "return type."); 469 } 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]; 476 } 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); 484 } 485 } 486 tokenizer.ExpectNextToken(";"); 487 } 488 489 void _ParseParameter(Tokenizer& tokenizer, Syscall& syscall) 490 { 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; 501 } 502 } 503 tokenizer.PutCurrentToken(); 504 if (type.size() < 2) { 505 if (type.size() == 1 && type[0] == "void") { 506 // that's OK 507 return; 508 } 509 throw ParseException("Error while parsing function parameter."); 510 } 511 512 // last component is the parameter name 513 string typeName = type.back(); 514 type.pop_back(); 515 516 string typeString(type[0]); 517 for (int i = 1; i < (int)type.size(); i++) { 518 typeString += " "; 519 typeString += type[i]; 520 } 521 syscall.AddParameter(NamedType(typeString, typeName)); 522 } 523 524 void _ParseFunctionPointerParameter(Tokenizer& tokenizer, Syscall& syscall, 525 vector<string>& type) 526 { 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."); 533 } 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."); 545 } 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]; 558 } 559 syscall.AddParameter(NamedType(typeString, typeName)); 560 } 561 562 private: 563 vector<Syscall> fSyscalls; 564 }; 565 566 567 int 568 main(int argc, char** argv) 569 { 570 try { 571 return Main().Run(argc, argv); 572 } catch (const Exception& exception) { 573 fprintf(stderr, "%s\n", exception.what()); 574 return 1; 575 } 576 } 577