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