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