1 /* 2 * Copyright 2004-2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 // Don't include arch_gensyscalls.h. It's only needed when creating the 7 // syscall vector. 8 #define DONT_INCLUDE_ARCH_GENSYSCALLS_H 1 9 10 #include <cstdio> 11 #include <cstdlib> 12 #include <fstream> 13 #include <string> 14 #include <vector> 15 16 #include "gensyscalls.h" 17 #include "gensyscalls_common.h" 18 19 using std::vector; 20 21 // usage 22 const char *kUsage = 23 "Usage: gensyscalls [ -c <calls> ] [ -d <dispatcher> ] [ -n <numbers> ]\n" 24 " [ -t <table> ] [ -s <strace> ]\n" 25 "\n" 26 "The command is able to generate several syscalls related source files.\n" 27 "\n" 28 " <calls> - Output: The assembly source file implementing the\n" 29 " actual syscalls.\n" 30 " <dispatcher> - Output: The C source file to be included by the\n" 31 " syscall dispatcher source file.\n" 32 " <numbers> - Output: The C/assembly include files defining the\n" 33 " syscall numbers.\n" 34 " <table> - Output: A C source file containing an array with\n" 35 " infos about the syscalls\n" 36 " <strace> - Output: A C source file for strace support.\n" 37 ; 38 39 // print_usage 40 static 41 void 42 print_usage(bool error) 43 { 44 fprintf((error ? stderr : stdout), kUsage); 45 } 46 47 48 // Type 49 50 // constructor 51 Type::Type(const char* name, int size, int usedSize, 52 const char* alignmentTypeName) 53 : fName(name), 54 fSize(size), 55 fUsedSize(usedSize), 56 fAlignmentType(alignmentTypeName) 57 { 58 } 59 60 61 // Parameter 62 63 // constructor 64 Parameter::Parameter(const char* typeName, const char* parameterName, 65 int size, int usedSize, int offset, const char* alignmentTypeName) 66 : Type(typeName, size, usedSize, alignmentTypeName), 67 fParameterName(parameterName), 68 fOffset(offset) 69 { 70 } 71 72 73 // Syscall 74 75 // ParameterVector 76 struct Syscall::ParameterVector : public vector<Parameter*> { 77 }; 78 79 // constructor 80 Syscall::Syscall(const char* name, const char* kernelName) 81 : fName(name), 82 fKernelName(kernelName), 83 fReturnType(NULL), 84 fParameters(new ParameterVector) 85 { 86 } 87 88 // destructor 89 Syscall::~Syscall() 90 { 91 delete fReturnType; 92 93 int count = CountParameters(); 94 for (int i = 0; i < count; i++) 95 delete ParameterAt(i); 96 delete fParameters; 97 } 98 99 // ParameterAt 100 int 101 Syscall::CountParameters() const 102 { 103 return fParameters->size(); 104 } 105 106 // ParameterAt 107 Parameter* 108 Syscall::ParameterAt(int index) const 109 { 110 if (index < 0 || index >= CountParameters()) 111 return NULL; 112 113 return (*fParameters)[index]; 114 } 115 116 // LastParameter 117 Parameter* 118 Syscall::LastParameter() const 119 { 120 return ParameterAt(CountParameters() - 1); 121 } 122 123 // SetReturnType 124 Type* 125 Syscall::SetReturnType(const char* name, int size, int usedSize, 126 const char* alignmentTypeName) 127 { 128 delete fReturnType; 129 return fReturnType = new Type(name, size, usedSize, alignmentTypeName); 130 } 131 132 // AddParameter 133 Parameter* 134 Syscall::AddParameter(const char* typeName, const char* parameterName, 135 int size, int usedSize, int offset, const char* alignmentTypeName) 136 { 137 Parameter* parameter = new Parameter(typeName, parameterName, size, 138 usedSize, offset, alignmentTypeName); 139 fParameters->push_back(parameter); 140 return parameter; 141 } 142 143 144 // SyscallVector 145 146 struct SyscallVector::_SyscallVector : public vector<Syscall*> { 147 }; 148 149 150 // constructor 151 SyscallVector::SyscallVector() 152 : fSyscalls(new _SyscallVector) 153 { 154 } 155 156 // destructor 157 SyscallVector::~SyscallVector() 158 { 159 int count = CountSyscalls(); 160 for (int i = 0; i < count; i++) 161 delete SyscallAt(i); 162 delete fSyscalls; 163 } 164 165 // Create 166 SyscallVector* 167 SyscallVector::Create() 168 { 169 return new SyscallVector; 170 } 171 172 // CountSyscalls 173 int 174 SyscallVector::CountSyscalls() const 175 { 176 return fSyscalls->size(); 177 } 178 179 // SyscallAt 180 Syscall* 181 SyscallVector::SyscallAt(int index) const 182 { 183 if (index < 0 || index >= CountSyscalls()) 184 return NULL; 185 186 return (*fSyscalls)[index]; 187 } 188 189 // CreateSyscall 190 Syscall* 191 SyscallVector::CreateSyscall(const char* name, const char* kernelName) 192 { 193 Syscall* syscall = new Syscall(name, kernelName); 194 fSyscalls->push_back(syscall); 195 return syscall; 196 } 197 198 199 // #pragma mark - 200 201 // Main 202 class Main { 203 public: 204 205 int Run(int argc, char **argv) 206 { 207 // parse arguments 208 const char *syscallsFile = NULL; 209 const char *dispatcherFile = NULL; 210 const char *numbersFile = NULL; 211 const char *tableFile = NULL; 212 const char *straceFile = NULL; 213 for (int argi = 1; argi < argc; argi++) { 214 string arg(argv[argi]); 215 if (arg == "-h" || arg == "--help") { 216 print_usage(false); 217 return 0; 218 } else if (arg == "-c") { 219 if (argi + 1 >= argc) { 220 print_usage(true); 221 return 1; 222 } 223 syscallsFile = argv[++argi]; 224 } else if (arg == "-d") { 225 if (argi + 1 >= argc) { 226 print_usage(true); 227 return 1; 228 } 229 dispatcherFile = argv[++argi]; 230 } else if (arg == "-n") { 231 if (argi + 1 >= argc) { 232 print_usage(true); 233 return 1; 234 } 235 numbersFile = argv[++argi]; 236 } else if (arg == "-t") { 237 if (argi + 1 >= argc) { 238 print_usage(true); 239 return 1; 240 } 241 tableFile = argv[++argi]; 242 } else if (arg == "-s") { 243 if (argi + 1 >= argc) { 244 print_usage(true); 245 return 1; 246 } 247 straceFile = argv[++argi]; 248 } else { 249 print_usage(true); 250 return 1; 251 } 252 } 253 fSyscallVector = create_syscall_vector(); 254 fSyscallCount = fSyscallVector->CountSyscalls(); 255 if (!syscallsFile && !dispatcherFile && !numbersFile && !tableFile 256 && !straceFile) { 257 printf("Found %d syscalls.\n", fSyscallCount); 258 return 0; 259 } 260 // generate the output 261 if (syscallsFile) 262 _WriteSyscallsFile(syscallsFile); 263 if (dispatcherFile) 264 _WriteDispatcherFile(dispatcherFile); 265 if (numbersFile) 266 _WriteNumbersFile(numbersFile); 267 if (tableFile) 268 _WriteTableFile(tableFile); 269 if (straceFile) 270 _WriteSTraceFile(straceFile); 271 return 0; 272 } 273 274 void _WriteSyscallsFile(const char *filename) 275 { 276 // open the syscalls output file 277 ofstream file(filename, ofstream::out | ofstream::trunc); 278 if (!file.is_open()) 279 throw IOException(string("Failed to open `") + filename + "'."); 280 281 // output the syscalls definitions 282 for (int i = 0; i < fSyscallCount; i++) { 283 const Syscall* syscall = fSyscallVector->SyscallAt(i); 284 int paramCount = syscall->CountParameters(); 285 int paramSize = 0; 286 // XXX: Currently the SYSCALL macros support 4 byte aligned 287 // parameters only. This has to change, of course. 288 for (int k = 0; k < paramCount; k++) { 289 const Parameter* parameter = syscall->ParameterAt(k); 290 int size = parameter->UsedSize(); 291 paramSize += (size + 3) / 4 * 4; 292 } 293 file << "SYSCALL" << (paramSize / 4) << "(" 294 << syscall->Name() << ", " << i << ")" << endl; 295 } 296 } 297 298 void _WriteDispatcherFile(const char *filename) 299 { 300 // open the dispatcher output file 301 ofstream file(filename, ofstream::out | ofstream::trunc); 302 if (!file.is_open()) 303 throw IOException(string("Failed to open `") + filename + "'."); 304 305 // output the case statements 306 for (int i = 0; i < fSyscallCount; i++) { 307 const Syscall* syscall = fSyscallVector->SyscallAt(i); 308 file << "case " << i << ":" << endl; 309 file << "\t"; 310 if (string(syscall->ReturnType()->TypeName()) != "void") 311 file << "*call_ret = "; 312 file << syscall->KernelName() << "("; 313 int paramCount = syscall->CountParameters(); 314 if (paramCount > 0) { 315 Parameter* parameter = syscall->ParameterAt(0); 316 if (parameter->AlignmentTypeName()) { 317 file << "(" << parameter->TypeName() << ")*(" 318 << parameter->AlignmentTypeName() 319 << "*)args"; 320 } else { 321 file << "*(" << _GetPointerType(parameter->TypeName()) 322 << ")args"; 323 } 324 for (int k = 1; k < paramCount; k++) { 325 parameter = syscall->ParameterAt(k); 326 if (parameter->AlignmentTypeName()) { 327 file << ", (" << parameter->TypeName() << ")*(" 328 << parameter->AlignmentTypeName() 329 << "*)((char*)args + " << parameter->Offset() 330 << ")"; 331 } else { 332 file << ", *(" << _GetPointerType(parameter->TypeName()) 333 << ")((char*)args + " << parameter->Offset() 334 << ")"; 335 } 336 } 337 } 338 file << ");" << endl; 339 file << "\tbreak;" << endl; 340 } 341 } 342 343 void _WriteNumbersFile(const char *filename) 344 { 345 // open the syscall numbers output file 346 ofstream file(filename, ofstream::out | ofstream::trunc); 347 if (!file.is_open()) 348 throw IOException(string("Failed to open `") + filename + "'."); 349 350 // output the defines 351 const char *prefix = "_user_"; 352 size_t prefixLen = strlen(prefix); 353 for (int i = 0; i < fSyscallCount; i++) { 354 const Syscall* syscall = fSyscallVector->SyscallAt(i); 355 string name(syscall->KernelName()); 356 357 // drop the leading "_user_" prefix 358 if (name.find(prefix) != 0) 359 throw Exception(string("Bad kernel name: `") + name + "'."); 360 name = string(name, prefixLen); 361 362 // convert to upper case (is there no function for that?) 363 string defineName; 364 for (int k = 0; k < (int)name.length(); k++) 365 defineName += toupper(name[k]); 366 file << "#define SYSCALL_" << defineName << " " << i << endl; 367 } 368 } 369 370 void _WriteTableFile(const char *filename) 371 { 372 // open the syscall table output file 373 ofstream file(filename, ofstream::out | ofstream::trunc); 374 if (!file.is_open()) 375 throw IOException(string("Failed to open `") + filename + "'."); 376 377 // output syscall count macro 378 file << "#define SYSCALL_COUNT " << fSyscallCount << endl; 379 file << endl; 380 381 // assembler guard 382 file << "#ifndef _ASSEMBLER" << endl; 383 file << endl; 384 385 // output syscall count 386 file << "const int kSyscallCount = SYSCALL_COUNT;" << endl; 387 file << endl; 388 389 // syscall infos array preamble 390 file << "const syscall_info kSyscallInfos[] = {" << endl; 391 392 // the syscall infos 393 for (int i = 0; i < fSyscallCount; i++) { 394 const Syscall* syscall = fSyscallVector->SyscallAt(i); 395 396 // get the parameter size 397 int paramSize = 0; 398 if (Parameter* parameter = syscall->LastParameter()) 399 paramSize = parameter->Offset() + parameter->UsedSize(); 400 401 // output the info for the syscall 402 file << "\t{ (void *)" << syscall->KernelName() << ", " 403 << paramSize << " }," << endl; 404 } 405 406 // syscall infos array end 407 file << "};" << endl; 408 file << endl; 409 410 // syscall parameters infos array preamble 411 file << "const extended_syscall_info kExtendedSyscallInfos[] = {" 412 << endl; 413 414 // the syscall parameters infos 415 for (int i = 0; i < fSyscallCount; i++) { 416 const Syscall* syscall = fSyscallVector->SyscallAt(i); 417 int paramCount = syscall->CountParameters(); 418 419 file << "\t{" << endl; 420 file << "\t\t\"" << syscall->Name() << "\", " << paramCount << "," 421 << endl; 422 file << "\t\t{" << endl; 423 424 for (int k = 0; k < paramCount; k++) { 425 const Parameter* parameter = syscall->ParameterAt(k); 426 file << "\t\t\t{ " << parameter->Offset() << ", " 427 << parameter->Size() << ", " 428 << parameter->UsedSize() << ", " 429 << _GetTypeCode(parameter) << " }," << endl; 430 } 431 432 file << "\t\t}" << endl; 433 file << "\t}," << endl; 434 } 435 436 // syscall parameters infos array end 437 file << "};" << endl; 438 439 // assembler guard end 440 file << "#endif // _ASSEMBLER" << endl; 441 } 442 443 void _WriteSTraceFile(const char *filename) 444 { 445 // open the syscall table output file 446 ofstream file(filename, ofstream::out | ofstream::trunc); 447 if (!file.is_open()) 448 throw IOException(string("Failed to open `") + filename + "'."); 449 450 // the file defines a single function get_syscalls 451 file << "void" << endl 452 << "GET_SYSCALLS(vector<Syscall*> &syscalls)" << endl 453 << "{" << endl 454 << "\tSyscall *syscall;" << endl 455 << "\tTypeHandler *handler;" << endl 456 << "(void)syscall;" << endl 457 << "(void)handler;" << endl; 458 459 int chunkSize = (fSyscallCount + 19) / 20; 460 461 // iterate through the syscalls 462 for (int i = 0; i < fSyscallCount; i++) { 463 const Syscall* syscall = fSyscallVector->SyscallAt(i); 464 465 if (i % chunkSize == 0) { 466 // chunk end 467 file << endl; 468 if (i > 0) 469 file << "#endif" << endl; 470 // chunk begin 471 file << "#ifdef SYSCALLS_CHUNK_" << (i / chunkSize) << endl; 472 } 473 474 // spacing, comment 475 file << endl; 476 file << "\t// " << syscall->Name() << endl; 477 478 // create the return type handler 479 const char* returnType = syscall->ReturnType()->TypeName(); 480 file << "\thandler = TypeHandlerFactory<" 481 << returnType 482 << ">::Create();" << endl; 483 484 // create the syscall 485 file << "\tsyscall = new Syscall(\"" << syscall->Name() << "\", " 486 << "\"" << returnType << "\", "<< "handler);" << endl; 487 file << "\tsyscalls.push_back(syscall);" << endl; 488 489 // add the parameters 490 int paramCount = syscall->CountParameters(); 491 for (int k = 0; k < paramCount; k++) { 492 const Parameter* parameter = syscall->ParameterAt(k); 493 494 // create the parameter type handler 495 file << "\thandler = TypeHandlerFactory<" 496 << parameter->TypeName() << ">::Create();" << endl; 497 498 // add the parameter 499 file << "\tsyscall->AddParameter(\"" 500 << parameter->ParameterName() << "\", " 501 << parameter->Offset() << ", \"" << parameter->TypeName() 502 << "\", handler);" << endl; 503 } 504 } 505 506 // last syscall chunk end 507 file << "#endif" << endl; 508 509 // function end 510 file << "}" << endl; 511 } 512 513 static string _GetPointerType(const char *type) 514 { 515 char *parenthesis = strchr(type, ')'); 516 if (!parenthesis) 517 return string(type) + "*"; 518 // function pointer type 519 return string(type, parenthesis - type) + "*" + parenthesis; 520 } 521 522 static string _GetTypeCode(const Type* type) 523 { 524 const char* typeName = type->TypeName(); 525 if (strchr(typeName, '*')) { 526 // pointer type 527 // check, if it is a string constant ("const char *" or 528 // "char const *") 529 if (_GetTypeCodeTokenize(typeName) == "const" 530 && _GetTypeCodeTokenize(typeName) == "char" 531 && _GetTypeCodeTokenize(typeName) == "*" 532 && _GetTypeCodeTokenize(typeName) == "" 533 || _GetTypeCodeTokenize(typeName) == "char" 534 && _GetTypeCodeTokenize(typeName) == "const" 535 && _GetTypeCodeTokenize(typeName) == "*" 536 && _GetTypeCodeTokenize(typeName) == "") { 537 return "B_STRING_TYPE"; 538 } 539 540 // not a string constant 541 return "B_POINTER_TYPE"; 542 } else { 543 // non-pointer type 544 switch (type->Size()) { 545 case 1: 546 return "B_INT8_TYPE"; 547 case 2: 548 return "B_INT16_TYPE"; 549 case 4: 550 return "B_INT32_TYPE"; 551 case 8: 552 return "B_INT64_TYPE"; 553 default: 554 return "B_RAW_TYPE"; 555 } 556 } 557 } 558 559 static string _GetTypeCodeTokenize(const char*& type) 560 { 561 // skip whitespace 562 while (*type != '\0' && isspace(*type)) 563 type++; 564 565 switch (*type) { 566 case '\0': 567 return ""; 568 569 case '*': 570 case '(': 571 case ')': 572 case '&': 573 return string(type++, 1); 574 575 default: 576 { 577 if (*type != '_' && !isalpha(*type)) { 578 // probably invalid, just return something 579 return string(type++, 1); 580 } 581 582 // an identifier 583 const char* start = type; 584 while (*type == '_' || isalnum(*type)) 585 type++; 586 return string(start, type - start); 587 } 588 } 589 } 590 591 private: 592 SyscallVector* fSyscallVector; 593 int fSyscallCount; 594 }; 595 596 // main 597 int 598 main(int argc, char **argv) 599 { 600 try { 601 return Main().Run(argc, argv); 602 } catch (Exception &exception) { 603 fprintf(stderr, "%s\n", exception.what()); 604 return 1; 605 } 606 } 607