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